Merge upstream - #201
Merge upstream#201
Conversation
Pinning `cloudflare/wrangler-action` does not pin the `wrangler@4` package it installs during deployment. Install Wrangler from a dedicated, committed lockfile with lifecycle scripts disabled, then invoke that local executable directly. Require `npm>=11.10.0` with `engines.npm` and `engine-strict` so older clients cannot silently ignore the seven-day `min-release-age` policy, and pin Node.js to `24.19.0` at the install sites. Both playgrounds now use the reviewed dependency tree already recorded for the playground API, and Cloudflare credentials are passed only to the deployment command. Related: astral-sh/ruff#27839 isolates the playground builds from deployment credentials, and astral-sh/ruff#27844 enforces the corresponding `npm` floor in the existing package roots. astral-sh/ruff-vscode#1152 and astral-sh/ty-vscode#526 likewise give credentialed publishers their own locked toolchains. --------- Co-authored-by: zaniebot <[email protected]>
Fixes astral-sh/ty#4308 by separating two questions: does a parameter have a default, and what type does that default expression have? ## The failure This small example currently causes ty to panic with `too many cycle iterations`: ```python f = lambda: f assert f @Property def f(x=lambda: f): ... ``` To determine what arguments the decorated function accepts, ty currently infers the types of all its defaults. Here, looking into `lambda: f` leads back to the decorated `f`, through the earlier assertion, and into the same inference work again. The repeated attempts never settle. The fix is to let ty determine that `x` has a default value (can be omitted from calls) without first working out the type of `lambda: f`. ## What changes Consider an ordinary function and a caller in another file: ```python # defaults.py def f(x: int = 1) -> int: return x ``` ```python # main.py from defaults import f result = f() ``` Checking the call needs to know that `x` accepts an `int` and can be omitted. It does not need the particular default value. Changing `1` to `2` therefore does not require rechecking this caller. Removing the default does: `f()` becomes an error. Default expressions are still checked when checking the file that defines the function. Code that genuinely needs the default's type can request it separately. For example, changing a custom dataclass field helper's `init` default from `False` to `True` must still update the generated constructor. ## Implementation Source parameters keep a reference to their definition instead of storing an already-inferred default type. `has_default()` answers whether an argument may be omitted; `default_type(db)` resolves the type when needed. Annotations remain in the existing `infer_deferred_types` cache. A separate `infer_function_default_types` cache contains only defaults, and normal file checking combines the two results. This avoids storing annotation data twice. Functions with only annotations or only defaults also avoid creating an empty second result. Overall this reduces memory usage relative to main. One awkward point in the implementation is that prior to this PR, a literal promotion type mapping also promotes the literal types of default values. Preserving this behavior would require an additional `DeferredPromoted` default-value enum type, to track the need for promotion of deferred defaults. But IMO it does not make sense that literal-promoting a callable type would literal-promote the types of its default values, which strictly speaking aren't even part of the callable type. So I just removed that entirely. This shows up in the ecosystem as some signatures now showing actual defaults rather than `...`, because we preserve literal default values when displaying types but transform nominal types to `...`. I think we probably need a more coherent policy around always erasing specific default types from general callable types, but that's too far afield for this PR. ## Test plan - Cycle mdtests cover the reported example, annotated variants, direct `property(...)` construction, a custom decorator, a ParamSpec decorator that changes the call signature, and a generic property getter. - A decorator mdtest checks that reporting an unknown decorator return handles a self-referential default and still identifies the function's signature. - Incremental tests check that ordinary calls do not infer defaults. Changing only a default value leaves those callers alone; removing and restoring the default updates missing-argument errors. Concrete signature display reflects the new value. - A dataclass regression changes a field helper's `init` default from `False` to `True` and back, checking the generated constructor's call diagnostics. - Cache tests verify that annotation and default results remain separate, and that functions needing only one do not create the other. - A promotion mdtest checks that a `partial` retains both its source default and a keyword-bound default when placed in a collection. ### Ecosystem Some duplicate diagnostics go away because main double-inferred a function's decorators when deferred annotations or defaults were inferred; this PR fixes that. Other changes are the default-values promotion change mentioned above.
CodSpeed's dependency installation can stall on an unhealthy apt mirror. Apply the mitigation from astral-sh/uv#21206 so apt gives up on failed downloads sooner and can reach its configured fallback mirrors. Immediately before CodSpeed runs, disable apt download retries and set ten-second HTTP and HTTPS timeouts. Apply this to the Ruff instrumented job and the simulation entries in the ty instrumented matrix. Leave build-only, memory-only, and walltime jobs unchanged. This does not change CodSpeed's cache detection. If every configured mirror is unavailable, installation may fail sooner rather than succeed. ## Test plan No new mdtests are needed for this workflow-only change. Validate the workflow's formatting, schema, security checks, and shell syntax. CI exercises the Ruff instrumented job and ty simulation matrix with the new apt configuration.
## Summary When an `invalid-assignment` diagnostic is caused by a previously declared type, point directly to the annotation that established that type instead of only annotating the assignment target. ## Example ```py value: int value = "three" ``` ```text error[invalid-assignment]: Object of type `Literal["three"]` is not assignable to `int` --> example.py:2:9 | 1 | value: int | --- Declared type 2 | value = "three" | ^^^^^^^ Incompatible value of type `Literal["three"]` ```
Bounded intersection expansion could silently drop alternatives after the first four members of a union. The first union is intentionally exempt from the expansion budget, but ignoring a failed insertion did not actually insert the omitted member. This let the helper return a partial type as though it were exact, causing false-positive diagnostics such as the regression exposed by #27664. Apply the budget exemption inside candidate insertion. Preserve every alternative of the first union, while continuing to return `None` if later expansion exceeds the budget. Fixes astral-sh/ty#4335. ## Test plan - Unit tests cover late union members surviving an intersection in either operand order, the single-union fast path, and genuine budget exhaustion returning `None` instead of a partial result. - Mdtests cover redundant upper bounds on five-member gradual unions, including a reduced recursive-alias regression with `Divergent` members.
(Stacked on top of #27872) ## Summary Add a disabled-by-default `unsound-assignment` rule for variable assignments whose inferred value is assignable to a fully static declared type but is not a subtype of it. Attribute and subscript assignments are deliberately excluded from this initial implementation. Share declaration lookup and diagnostic rendering with `invalid-assignment` so the rule points to the annotation responsible for the expected type, including parameters, variadics, global/nonlocal bindings, and augmented assignments. Fixes astral-sh/ty#4289.
## Summary Specializing a non-generic class in a type expression currently emits `not-subscriptable`, even when the class defines `__class_getitem__` and subscription works at runtime. Report `invalid-type-form` instead, explaining that the class cannot be specialized in a type expression and linking to the typing specification. Apply the correction both to direct annotations and to specializations nested inside `type[...]`. Keep `Unknown` recovery and runtime subscription behavior unchanged. Existing suppressions of `not-subscriptable` no longer suppress these type-form errors; projects that intentionally ignore them can suppress `invalid-type-form` instead. Fixes astral-sh/ty#4331. ## Test plan Update the existing non-generic-class expectations. Add mdtests covering custom `__class_getitem__` in value expressions, direct and nested type annotations, future annotations, Python 3.14's deferred annotations, and the full diagnostic output.
`scripts/release.sh` uses `--no-config` to avoid recording Socket's registry URLs, but this also discards `exclude-newer` and other configuration. Set `--default-index` to PyPI for the lockfile update and crates.io publishing check so these commands use the public default index while retaining the remaining settings. Co-authored-by: zaniebot <[email protected]>
…erenced by `from ...` imports (#27905) <!-- Thank you for contributing to Ruff/ty! To help us out with reviewing, please consider the following: - Does this pull request include a summary of the change? (See below.) - Does this pull request include a descriptive title? (Please prefix with `[ty]` for ty pull requests.) - Does this pull request include references to any relevant issues? - Does this PR follow our AI policy (https://github.com/astral-sh/.github/blob/main/AI_POLICY.md)? --> ## Summary <!-- What's the purpose of the change? What does it do, and why? --> This reduces some unnecessary duplication across code that resolves a module for a `from ...` import. ## Test Plan This is a pure refactor that relies on existing test coverage. <!-- How was it tested? -->
…7772) This is the first prerequisite for fixing the performance issues in astral-sh/ty#4269. It makes ty's existing shortcut for comparing recursive protocols more accurate, without adding the later performance optimizations. ## Keep the methods needed for comparison A recursive protocol can send the type checker back through the same requirements repeatedly. To avoid that, ty can first compare the requirements that do not refer back to the protocol. The problem was that it removed recursive-looking members from *both* types being compared. A member of the actual type can mention the protocol even when the corresponding requirement does not, so removing it loses information needed to decide whether the types are compatible. For example: ```python from __future__ import annotations from typing import Protocol class Consumer[T](Protocol): def consume(self, value: T | int) -> None: ... @Property def child(self) -> Consumer[T]: ... def extract[T](consumer: Consumer[T]) -> T: raise NotImplementedError def check(value: Consumer[Consumer[int]]) -> None: reveal_type(extract(value)) # Before: Consumer[int] # After: Consumer[int] | int ``` Here, the actual `consume` method accepts `Consumer[int] | int`. Its annotation mentions `Consumer`, so the old shortcut could discard the method and infer only `Consumer[int]` from the class's type arguments. Keeping the method available preserves the additional `int` possibility. This PR filters only the requirements of the expected protocol, while keeping every member of the actual type available to satisfy those requirements. It also uses ordinary matching when the expected protocol has no recursive requirements, even if the actual type contains a nested use of the same protocol. ## Distinguish repeated aliases from recursion ty tries to compare simple protocol members before members that can lead back into another protocol comparison. Previously, any type alias caused a member to be put in the potentially recursive group, even when the alias was just another name for `int`. The new traversal follows alias definitions before making that decision. Reusing an ordinary alias does not itself create a cycle: ```python type Identity[T] = T # This expands completely to int. type Example = Identity[Identity[int]] ``` But an actually recursive alias can keep changing its type arguments as it expands: ```python type Growing[T] = T | Growing[list[T]] # Growing[int] leads to Growing[list[int]], then # Growing[list[list[int]]], and so on. ``` For a recursive alias, the traversal stops when it reaches a definition it is already expanding, even if the type arguments have changed. Ordinary alias applications remain distinct, so nested uses such as `Identity[Identity[int]]` are still recognized as non-recursive. ty can answer this question without expanding the rest of a protocol's members. ## Test plan The added protocol mdtests cover: - A non-recursive expected protocol whose actual type contains a nested use of that protocol. - Recursive protocol members that contribute the full `Consumer[int] | int` inference shown above. - Nested applications of a non-recursive generic alias that must still contribute to type inference. - A recursive alias whose type arguments grow, checking that comparison terminates and still rejects an incompatible assignment.
…icts (#27914)
## Summary
Follow-up to #27882.
Previously, changing deferred lookup modes while inferring `Annotated`
metadata could discard the enclosing string-annotation context, causing
parsed expressions to be looked up in the module's semantic index and
panic:
```python
from typing_extensions import Annotated, TypedDict
value: "Annotated[int, lambda default=int: None]"
other: "Annotated[int, TypedDict('T', {}, extra_items=int)]"
```
We now preserve `InStringAnnotation` while inferring lambda defaults.
For `TypedDict.extra_items`, we pass through the existing state and rely
on annotation inference to defer stub annotations without losing their
enclosing string context. This also covers nested lambdas, dynamic
classes in defaults, and positional-only and keyword-only stub defaults.
All 838 semantic tests pass.
## Summary Follow-up to #27882. Previously, the non-generic-class and `type[...]` fallback paths could evaluate invalid subscript arguments inside string annotations, reaching assignment expressions that are absent from the semantic index: ```python value: "int[(other := 0)]" another: "type[(other := 0)]" ``` We now skip expression inference in these error-recovery paths when the arguments come from a string annotation. Non-generic classes retain their existing `invalid-type-form` diagnostic, unsupported `type[...]` forms retain their existing fallback type, and evaluated annotations retain their runtime diagnostics. We do not add support for additional `type[...]` forms. This fix is independent of #27914 and #27913.
## Summary Skip checking scripts with invalid PEP 723 metadata blocks, that are, blocks that ty can't parse successfully or configurations that don't resolve successfully. Instead, emit one diagnostic that points to the invalid metadata. ty still initializes a `Program` for each of those scripts so that LSP operations continue to work. But we skip those scripts in all code paths where we perform semantic checks. Fixes astral-sh/ty#4181. ## Test plan Added tests
## Summary Add a CodSpeed baseline for checking a PEP 723 script that imports a declared dependency. The following CLI integration PR uses the same benchmark to measure warm-cache uv synchronization overhead and catch regressions. Testing: Ran the benchmark in the profiling profile and checked the affected benchmark target.
## Summary Enable the new automatic "sync script virtual environment" in ecosystem runs. This ensures that scripts will be checked with their own virtual environment and own dependencies (at least, once PRs later in this stack land). I decided to only enable the new scripts behavior because enabling the new automatic uv sync for all projects breaks mypy primer, because uv now tries to install all dependencies of that project which may not succeed. We'll need to find a solution for this, but I prefer to solve this later
## Summary
Previously, narrowing was lost after a statically known branch because
the unreachable control-flow path still contributed its original type:
```python
def narrow(value: int | None) -> None:
if 1 + 1 == 2:
if value is None:
return
reveal_type(value) # Previously: int | None; now: int
```
We now gate narrowing constraints with their corresponding reachability
conditions and reuse predicate identities across both analyses. This
allows narrowing to propagate through constant conditions, short-circuit
expressions, match guards, and statically non-empty `range()` loops
while preserving ambiguous branches.
Statement-level calls now participate in normal reachability analysis in
every scope, replacing the separate scope-wide narrowing machinery for
module- and class-level calls. As a result, the improved narrowing also
works inside module- and class-level loops, while preserving
terminal-call analysis, overload selection, and loop-carried forward
references.
Because these calls now contribute to reachability graphs, we raise the
nested-binding cutoff from 2,048 to 4,096 to preserve precision in
call-heavy scopes. The loop-reachability and loop-inference cutoffs
remain unchanged to protect performance on loop-heavy projects such as
isort and parso.
We also track the places each predicate can narrow, avoiding unnecessary
constraint inference and preventing unrelated reachability gates from
introducing cycles through deferred annotations. Lambda and generator
conditions are resolved without inferring their bodies, avoiding
recursive-callable inference cycles.
This also fixes exhaustive nested checks where proving that an outer
branch terminates depends on narrowing a separate inner value,
preventing spurious `assert_never` errors.
Based on @mtshiba's work in #27207 and #23201.
Closes astral-sh/ty#4240.
---------
Co-authored-by: Shunsuke Shibayama <[email protected]>
Summary -- Addresses astral-sh/ruff#27666 (comment), where we want to start using "group" to refer to secondary categories. This type is already referred to as `status` in the user-facing JSON output, so this change aligns the internal type name with that usage. Test Plan -- Existing tests
Generic classes inheriting recursive protocols can repeatedly expand the same protocol interface when contextual constructor inference or diagnostic collection binds explicitly constrained method receivers. Programs with several inherited recursive members then become pathologically slow. Check finite requirements first for nominally inherited protocols, and stop expanding recursive requirements once their constraints establish the inherited relationship. Preserve full structural checking when it remains necessary for erased type parameters, overridden requirements, concrete-source inference, or diagnostic explanations. Also restrict eager receiver-compatibility checks to overload selection, where they actually prune candidates, so single-method binding does not recursively re-enter the protocol. Part of astral-sh/ty#4269. ## Ecosystem impact Werkzeug gains two overload errors and two unused-ignore warnings because improved contextual inference preserves the actual `sorted` callback argument instead of widening it to `object`. This exposes its existing `int | None` sort key; the old lambda-line ignore no longer covers the call-level error. ## Test plan - Protocol mdtests cover contextual constructor inference, invalid constructor arguments, empty-iterable `Never` inference, concrete/symbolic/unknown constrained receivers, erased type parameters recovered structurally, and overridden recursive requirements. - A diagnostic snapshot preserves nested protocol-member explanations during context collection. - A constraint-support test verifies exact type-variable identities without treating declaration-default metadata as semantic support. - Separate benchmarks cover recursive-protocol constructor inference and diagnostic collection.
## Summary Previously, invalid `Literal` and `LiteralString` arguments inside string annotations could reach assignment expressions that are absent from the semantic index: ```python from typing import Literal, LiteralString value: "LiteralString[(other := 0)]" another: "Literal[int[(other := 0)]]" ``` We now infer both sides of assignment expressions in string annotations without looking up nonexistent semantic-index definitions. This avoids the panic while preserving unresolved-reference and other nested diagnostics for invalid `Literal` and `LiteralString` arguments. Evaluated annotations retain their existing inference and runtime diagnostics.
Summary -- Before this, running `./scripts/release.sh` produced this error on my machine: ```console ❯ ./scripts/release.sh Updating metadata with rooster... warning: `VIRTUAL_ENV=/Users/brw/.virtualenvs/openai` does not match the project environment path `.venv` and will be ig nored; use `--active` to target the active environment instead error: The lockfile at `uv.lock` needs to be updated, but `--locked` was provided. hint: To update the lockfile, run `uv lock`. ``` Passing an additional `--default-index` flag to the initial `uv run` also works, but it seems easier to export the environment variable for the whole workflow. Test Plan -- Manual testing in today's release
Summary -- This aligns the pre-commit hook with our release script ## Test plan Manual test on today's release branch
Sometimes Codex will write prose that assumes familiarity with the current session, a specific PR change, or the issue that triggered it. Add general guidance for writing mdtests, code comments, documentation, PR descriptions, and GitHub issues for their eventual readers, grounded in the final code and verified evidence. Keep mdtest-specific advice to explain behavior and its rationale directly, including a preference for "We reject this assignment" over "We must reject this assignment." Clarify that common behavior comes before specialized regressions, and that coherent subsections can be long when they contain short examples interspersed with prose. ## Test plan Guidance-only change; no runtime behavior or mdtest scenarios were added. File-scoped documentation hooks pass.
Summary -- This partially reverts astral-sh/ruff#27935 as an alternative to enabling preview everywhere. Preview was initially enabled ~2 years ago (#11496), and we probably want to be more selective about preview features now. Test Plan -- Today's release, previous errors: - https://github.com/astral-sh/ruff/actions/runs/32390111175/job/96493893174?pr=27937 - https://github.com/astral-sh/ruff/actions/runs/32390111175/job/96493998150?pr=27937
The playground release jobs run `npm run check` and the builds on the runner that later receives `CF_API_TOKEN`. Move those commands into unprivileged jobs and pass named, digest-verified static artifacts to fresh `release-playground` jobs. The publishers reject symlinks, special files, and Pages server-code entrypoints before deployment. This isolates the playground build tools; it does not remove the publisher's Wrangler dependency. Locking that tooling is handled separately in astral-sh/ruff#27838. Related: astral-sh/ruff-vscode#1152 and astral-sh/ty-vscode#526 reduce the dependency trees installed by the marketplace publishers. --------- Co-authored-by: zaniebot <[email protected]>
## Summary Fix the subtype check in [Alex's example](astral-sh/ruff#28246 (review)): we treat `InvalidOverride` as a subtype, even though it overrides `read` incompatibly. ```python class Bounded[T: str](Protocol): def read(self) -> T: ... def other(self) -> Any: ... class InvalidOverride(Bounded[str]): read = None static_assert(is_subtype_of(InvalidOverride, Top[Bounded[Any]])) ``` ## Test strategy New Markdown tests
Summary -- This should avoid requesting review from owners of these crates for the automated version bumps, assuming they don't want to be notified :) Test Plan -- Future releases
…tring (`ISC003`) (#27981) Fixes #27979 Removing the `+` from the first statement of a module, function, or class body turns the concatenation into a docstring, changing `__doc__` and program behavior. Detect docstring positions and emit the fix with unsafe safety level instead. - Concats of plain string literals only (f-strings, bytes, t-strings can never be docstrings) - Covers module, function, class, and method bodies - Safe fix behavior unchanged for non-docstring positions ## Test Plan `cargo test -p ruff_linter --lib` (2813 pass), clippy + fmt clean --------- Co-authored-by: Brent Westbrook <[email protected]>
Calling `dict(a=1)` can panic when a first-party `typing.py` hides typeshed's generic definitions. Preserve key/value indices during fallback inference and recover with `Unknown` after checking the values, avoiding a second inference pass. Empty calls and specialization failures retain ordinary constructor validation so their diagnostics are preserved. Fixes astral-sh/ty#4454. ## Test plan Added mdtests for one and multiple named keywords with an empty `typing.py`, diagnostics in keyword values, empty calls to a non-generic dictionary requiring an argument, and a bounded dictionary value type that reports both an invalid argument and a later unresolved name.
Pure refactoring PR to reduce the diff on astral-sh/ruff#26873.
String member lookup can panic when a first-party `typing.py` introduces an inference cycle through class and metaclass resolution. Add cycle recovery to `known_class_to_instance` so inference can converge and checking reports the ordinary diagnostics. Fixes astral-sh/ty#4456. ## Test plan Add mdtests with a local `typing.py` whose function call requires resolving an unknown metaclass before a `Sequence` binding. Check the consumer both before and after the shadowing module. Both scenarios verify that `str.encode()` retains its `bytes` return type and that the unresolved metaclass produces the expected diagnostic.
…straints (#28297)
During fixpoint iteration, we use argument types inferred from previous
iterations as type context for subsequent iterations. Arguments being
forwarded to a `ParamSpec` are initially inferred without type context,
as the type of the callable has not yet been inferred, and so we clear
their types after the initial iteration. However, we currently fallback
to `Unknown` as type context for arguments that have not yet been
inferred, even if they have been intentionally cleared, which can
pollute the types inferred in the next iteration. We should instead
avoid providing any type context in this case.
```py
from typing import TypedDict, Callable
class Payload(TypedDict):
x: int
def forward[**P](function: Callable[P, None], /, *args: P.args, **kwargs: P.kwargs) -> None:
function(*args, **kwargs)
def pair[T](first: T, second: T) -> None: ...
def _(payload: Payload):
forward(pair, reveal_type({"x": 1}), payload) # main: dict[str, int], fixed: Payload
```
## Summary Projects that extend the same Ruff configuration repeatedly parse its options and compile inherited per-file globs during file discovery. Reuse that work within each traversal to reduce configuration overhead when checking many projects. Cache parsed and normalized configurations by file path and normalization root, before inheritance merging and CLI overrides. Share per-file glob compilation across configuration clones, preserving the existing post-override compilation order and matching behavior. Reuse path candidates during matching and skip empty per-file target-version lookups. The cache lasts for one traversal; later traversals reload configurations. Parsing stays outside the cache lock so unrelated files can load in parallel. Concurrent misses can load the same file more than once. ## Test Plan Existing CLI and workspace regressions pass for inherited configuration errors, relative paths, CLI overrides, negated per-file ignores, and target versions for linting and formatting. No snapshots changed. --------- Co-authored-by: Charlie Marsh <[email protected]>
<!-- Thank you for contributing to Ruff/ty! To help us out with reviewing, please consider the following: - Does this pull request include a summary of the change? (See below.) - Does this pull request include a descriptive title? (Please prefix with `[ty]` for ty pull requests.) - Does this pull request include references to any relevant issues? - Does this PR follow our AI policy (https://github.com/astral-sh/.github/blob/main/AI_POLICY.md)? --> ## Summary As previewed in astral-sh/ruff#27834 (comment), this introduces a semantic model of the tests that pytest recognizes in a particular file or for a particular candidate function. This model will ultimately be shared by several features (e.g., astral-sh/ty#4119 and astral-sh/ty#4041), and it is [immediately integrated into our semantic model for pytest fixtures](astral-sh/ruff#27974) (which powers "Go to definition" and "Find references" in the language server). ## Test Plan See included tests. <!-- How was it tested? -->
… collection model (#27974) <!-- Thank you for contributing to Ruff/ty! To help us out with reviewing, please consider the following: - Does this pull request include a summary of the change? (See below.) - Does this pull request include a descriptive title? (Please prefix with `[ty]` for ty pull requests.) - Does this pull request include references to any relevant issues? - Does this PR follow our AI policy (https://github.com/astral-sh/.github/blob/main/AI_POLICY.md)? --> ## Summary <!-- What's the purpose of the change? What does it do, and why? --> This incorporates the shared model for pytest test collection into the model of pytest fixture bindings which powers "Go to definition" and "Find references" on test parameters in the language server. ## Test Plan This is a refactor that relies on existing test coverage. <!-- How was it tested? -->
## Summary Linux release smoke tests currently install packages on the runner or in containers with writable workspace mounts. Run them through the shared [release-smoke-test action](astral-sh/github-actions#1), which mounts completed artifacts read-only. Keep the existing smoke commands and target exclusions, and pin the test images. Select the installed Rust toolchain as the container default so pip can invoke Cargo from its temporary build directories. ## Test plan - [x] Ensure the PR's Build binaries jobs run and succeed, including sdist and wheel smoke tests using the pinned shared action on native and emulated architectures.
We use callable types to represent the values that a `ParamSpec` can specialize to. They only bind the parameters of a signature, though, not its return type annotation. So we normalize `paramspec_value` callables by removing their return type. Internally, missing return types are treated the same as `Unknown`. This means we were erroneously considering _all_ `paramspec_value` callables to be dynamic, since they contained a dynamic return type, even if all of the parameter annotations were fully static. To fix this, I updated our default `TypeVisitor` `walk_callable` logic to skip the return type entirely for `paramspec_value` callables, since they are genuinely missing, not just implicitly `Unknown`. (I think we use to model this separately, by storing the return type as an `Option<Type>`, but going back to that seemed to be a deeper change than was warranted.)
When inferring a callable against a declared callable type with a
`ParamSpec`, constraints from the outer assignability check may leak
their way into the inferred `ParamSpec` type. This can happen
particularly with callables with a declared return types of `Any`. For
example:
```py
from typing import Callable, Any
class Wrapper[**P]:
def __call__(self, *args: P.args, **kwargs: P.kwargs) -> Any:
raise NotImplementedError
def decorate[**P](callback: Callable[P, Any]) -> Wrapper[P]:
raise NotImplementedError
def _[T](callback: Callable[[T], T]) -> None:
reveal_type(decorate(callback)) # revealed: Wrapper[((T@_, /)) | ((Any, /))]
```
On astral-sh/ruff#26873, the same problem arises
with callable-scoped type variables.
This PR adds a very narrow short-circuit to ignore the gradual
constraint in this particular case. The more principled fix probably
resolves around [the quantification of signature-local
variables](https://github.com/astral-sh/ruff/blob/3070999871911cf59dca7ecd9e453d984314924c/crates/ty_python_semantic/src/types/signatures.rs#L2402)
which [`ParamSpec` inference currently
bypasses](https://github.com/astral-sh/ruff/blob/3070999871911cf59dca7ecd9e453d984314924c/crates/ty_python_semantic/src/types/signatures.rs#L2273),
as the naive quantification would lose constraints that should correctly
be applied to the inferred `ParamSpec`.
cc @dhruvmanila
---------
Co-authored-by: David Peter <[email protected]>
## Summary We retain separate binding and declaration tables for every scope in a file, even when those tables contain identical scope-local IDs. The duplicate storage accounts for a measurable share of the semantic index in representative projects. We now share equivalent immutable tables across scopes while keeping each scope's definitions and constraints in its own `UseDefMap`. The interner is local to semantic-index construction, so its lookup sets do not remain in the retained index. Co-authored-by: Charlie Marsh <[email protected]>
<!-- Thank you for contributing to Ruff/ty! To help us out with reviewing, please consider the following: - Does this pull request include a summary of the change? (See below.) - Does this pull request include a descriptive title? (Please prefix with `[ty]` for ty pull requests.) - Does this pull request include references to any relevant issues? - Does this PR follow our AI policy (https://github.com/astral-sh/.github/blob/main/AI_POLICY.md)? --> ## Summary <!-- What's the purpose of the change? What does it do, and why? --> This moves the semantic model for pytest fixtures from `dedicated/pytest.rs`[^1] to `dedicated/pytest/fixtures.rs`, where it is now a sibling of other pytest sub-models, such as the test collection model at `dedicated/pytest/collection.rs`. [^1]: (in `crates/ty_python_semantic/src/types`) ## Test Plan This is a refactor that relies on existing test coverage. <!-- How was it tested? -->
370 commits from astral-sh/ruff (aug 12 → sep 4 2026). the typeshed is regenerated from upstream's `.pyi` rather than merged. the refactors that needed the fork's side rewritten rather than re-applied: variance is now a lazy equation (`VarianceTerm`) instead of an eagerly computed `TypeVarVariance`. `bivariant-private-attributes` rides on a keyed `variance_equation_with(db, typevar, flag)`, and `typevar_is_unused` reads the same equation with the flag off — which is what keeps the spec's "bivariant means unused" fallback separable from the fork's rule. `visit_expr` became `visit_expr_with_context`, so a condition and a value are told apart while the index is built. the fork's six additions moved into the new function, and `visit_if_condition` picks value context for an `if let` subject and condition context otherwise. a PEP 723 script's settings are resolved in `script.rs` now. the fork's rule — the script's block layers over the project's configuration rather than replacing it — is re-implemented in `resolve_script_options`, and `[tool.basedpython]` reads there as it does everywhere else. a per-file `[[overrides]]` block no longer reaches a script. the ABC relocation waits for the pep 695 conversion. it moves classes as source text, and reading them before `typing` was converted put 21 legacy `TypeVar` classes in `_collections_abc` referring to declarations that the conversion had already deleted. every lint rule now declares a category; the `BY` rules are `Style`. Co-Authored-By: Claude Opus 5 <[email protected]>
95510f0 to
3127563
Compare
ecosystem checkLinter (stable)ℹ️ ecosystem check detected linter changes. (+11 -2 violations, +0 -0 fixes in 3 projects; 56 projects unchanged) apache/airflow (+8 -0 violations, +0 -0 fixes)
ruff check --no-cache --exit-zero --no-fix --output-format concise --no-preview --select ALL
+ devel-common/src/tests_common/test_utils/logging_command_executor.py:37:20: S603 `subprocess` call: check for execution of untrusted input + devel-common/src/tests_common/test_utils/logging_command_executor.py:41:14: S603 `subprocess` call: check for execution of untrusted input + devel-common/src/tests_common/test_utils/logging_command_executor.py:59:14: S603 `subprocess` call: check for execution of untrusted input + devel-common/src/tests_common/test_utils/logging_command_executor.py:86:20: S603 `subprocess` call: check for execution of untrusted input + devel-common/src/tests_common/test_utils/logging_command_executor.py:90:14: S603 `subprocess` call: check for execution of untrusted input + providers/edge3/src/airflow/providers/edge3/example_dags/win_test.py:226:27: S602 `subprocess` call with `shell=True` identified, security issue + providers/google/src/airflow/providers/google/cloud/operators/gcs.py:1029:18: S603 `subprocess` call: check for execution of untrusted input + providers/google/src/airflow/providers/google/cloud/operators/gcs.py:711:18: S603 `subprocess` call: check for execution of untrusted input bokeh/bokeh (+2 -2 violations, +0 -0 fixes)
ruff check --no-cache --exit-zero --no-fix --output-format concise --no-preview --select ALL
+ src/bokeh/server/asgi.py:391:21: ASYNC240 Async functions should not perform blocking pathlib.Path operations - src/bokeh/server/asgi.py:391:21: ASYNC240 Async functions should not use pathlib.Path methods, use trio.Path or anyio.path + src/bokeh/server/views/static_handler.py:145:16: ASYNC240 Async functions should not perform blocking os.path operations - src/bokeh/server/views/static_handler.py:145:16: ASYNC240 Async functions should not use os.path methods, use trio.Path or anyio.path zulip/zulip (+1 -0 violations, +0 -0 fixes)
ruff check --no-cache --exit-zero --no-fix --output-format concise --no-preview --select ALL
+ zerver/openapi/javascript_examples.py:22:14: S607 Starting a process with a partial executable path Changes by rule (4 rules affected)
Linter (preview)ℹ️ ecosystem check detected linter changes. (+2327 -162 violations, +0 -0 fixes in 29 projects; 30 projects unchanged) aiven/aiven-client (+13 -0 violations, +0 -0 fixes)
ruff check --no-cache --exit-zero --no-fix --output-format concise --preview
+ aiven/client/argx.py:199:14: subclass-builtin Subclassing `dict` can be error prone, use `collections.UserDict` instead + aiven/client/argx.py:74:22: if-exp-instead-of-or-operator [*] Replace ternary `if` expression with `or` operator + aiven/client/cli.py:4501:46: unnecessary-dict-comprehension-for-iterable [*] Unnecessary dict comprehension for iterable; use `dict.fromkeys` instead + aiven/client/cli.py:6654:34: unnecessary-dict-comprehension-for-iterable [*] Unnecessary dict comprehension for iterable; use `dict.fromkeys` instead + aiven/client/cli.py:6765:34: unnecessary-dict-comprehension-for-iterable [*] Unnecessary dict comprehension for iterable; use `dict.fromkeys` instead + aiven/client/client.py:142:54: if-exp-instead-of-or-operator [*] Replace ternary `if` expression with `or` operator + aiven/client/client.py:856:20: if-exp-instead-of-or-operator [*] Replace ternary `if` expression with `or` operator + aiven/client/client.py:880:20: if-exp-instead-of-or-operator [*] Replace ternary `if` expression with `or` operator + aiven/client/connection_info/_utils.py:47:13: repeated-append Use `bits.extend((":", urllib.parse.quote(password)))` instead of repeatedly calling `bits.append()` + tests/test_cli.py:1505:5: pytest-raises-with-multiple-statements `pytest.raises()` block should contain a single simple statement ... 3 additional changes omitted for project PlasmaPy/PlasmaPy (+26 -0 violations, +0 -0 fixes)
ruff check --no-cache --exit-zero --no-fix --output-format concise --preview
+ docs/_author_list_from_cff.py:97:9: missing-f-string-syntax Possible f-string without an `f` prefix + docs/notebooks/formulary/ExB_drift.ipynb:cell 15:3:24: missing-f-string-syntax Possible f-string without an `f` prefix + docs/notebooks/formulary/ExB_drift.ipynb:cell 15:4:30: missing-f-string-syntax Possible f-string without an `f` prefix + src/plasmapy/analysis/fit_functions.py:584:12: float-equality-comparison Unreliable floating point equality comparison `m == 0.0` + src/plasmapy/analysis/swept_langmuir/floating_potential.py:243:17: float-equality-comparison Unreliable floating point equality comparison `current == 0.0` + src/plasmapy/formulary/quantum.py:123:10: float-equality-comparison Unreliable floating point equality comparison `0 * u.m / u.s == V` + src/plasmapy/plasma/grids.py:1373:26: float-equality-comparison Unreliable floating point equality comparison `norms == 0.0` + tests/analysis/test_fit_functions.py:534:16: float-equality-comparison Unreliable floating point equality comparison `root == np.log(5.0 / 3.0) / 0.5` + tests/formulary/test_fusion.py:326:16: float-equality-comparison Unreliable floating point equality comparison `sigma.unit == u.m**3 / u.s` ... 17 additional changes omitted for rule float-equality-comparison + tests/formulary/test_quantum.py:122:9: missing-f-string-syntax Possible f-string without an `f` prefix ... 16 additional changes omitted for project apache/airflow (+592 -0 violations, +0 -0 fixes)
ruff check --no-cache --exit-zero --no-fix --output-format concise --preview --select ALL
+ airflow-core/tests/conftest.py:166:17: pytest-fixture-autouse Avoid using `autouse=True` in `pytest.fixture` decorators + airflow-core/tests/system/conftest.py:34:17: pytest-fixture-autouse Avoid using `autouse=True` in `pytest.fixture` decorators + airflow-core/tests/unit/always/test_providers_manager.py:350:21: pytest-fixture-autouse Avoid using `autouse=True` in `pytest.fixture` decorators + airflow-core/tests/unit/always/test_providers_manager.py:93:21: pytest-fixture-autouse Avoid using `autouse=True` in `pytest.fixture` decorators + airflow-core/tests/unit/always/test_secrets_environment_variables.py:62:21: pytest-fixture-autouse Avoid using `autouse=True` in `pytest.fixture` decorators + airflow-core/tests/unit/api/common/test_airflow_health.py:308:21: pytest-fixture-autouse Avoid using `autouse=True` in `pytest.fixture` decorators ... 579 additional changes omitted for rule pytest-fixture-autouse + devel-common/src/tests_common/test_utils/logging_command_executor.py:37:20: subprocess-without-shell-equals-true `subprocess` call: check for execution of untrusted input + devel-common/src/tests_common/test_utils/logging_command_executor.py:41:14: subprocess-without-shell-equals-true `subprocess` call: check for execution of untrusted input + devel-common/src/tests_common/test_utils/logging_command_executor.py:59:14: subprocess-without-shell-equals-true `subprocess` call: check for execution of untrusted input + devel-common/src/tests_common/test_utils/logging_command_executor.py:86:20: subprocess-without-shell-equals-true `subprocess` call: check for execution of untrusted input + devel-common/src/tests_common/test_utils/logging_command_executor.py:90:14: subprocess-without-shell-equals-true `subprocess` call: check for execution of untrusted input ... 581 additional changes omitted for project apache/superset (+112 -0 violations, +0 -0 fixes)
ruff check --no-cache --exit-zero --no-fix --output-format concise --preview --select ALL
+ tests/integration_tests/celery_tests.py:71:17: pytest-fixture-autouse Avoid using `autouse=True` in `pytest.fixture` decorators + tests/integration_tests/charts/api_tests.py:94:21: pytest-fixture-autouse Avoid using `autouse=True` in `pytest.fixture` decorators + tests/integration_tests/charts/data/api_tests.py:131:17: pytest-fixture-autouse Avoid using `autouse=True` in `pytest.fixture` decorators + tests/integration_tests/charts/version_restore_tests.py:68:21: pytest-fixture-autouse Avoid using `autouse=True` in `pytest.fixture` decorators + tests/integration_tests/conftest.py:120:17: pytest-fixture-autouse Avoid using `autouse=True` in `pytest.fixture` decorators + tests/integration_tests/dao/base_dao_test.py:72:17: pytest-fixture-autouse Avoid using `autouse=True` in `pytest.fixture` decorators + tests/integration_tests/dao/conftest.py:46:33: pytest-fixture-autouse Avoid using `autouse=True` in `pytest.fixture` decorators + tests/integration_tests/dashboards/filter_state/api_tests.py:56:17: pytest-fixture-autouse Avoid using `autouse=True` in `pytest.fixture` decorators + tests/integration_tests/dashboards/update_tabs_test.py:41:17: pytest-fixture-autouse Avoid using `autouse=True` in `pytest.fixture` decorators + tests/integration_tests/dashboards/version_restore_tests.py:69:21: pytest-fixture-autouse Avoid using `autouse=True` in `pytest.fixture` decorators ... 102 additional changes omitted for project binary-husky/gpt_academic (+140 -34 violations, +0 -0 fixes)
ruff check --no-cache --exit-zero --no-fix --output-format concise --preview
- crazy_functions/Academic_Conversation.py:162:28: call-datetime-now-without-tzinfo `datetime.datetime.now()` called without a `tz` argument + crazy_functions/Conversation_To_File.py:199:17: if-exp-instead-of-or-operator [*] Replace ternary `if` expression with `or` operator + crazy_functions/Conversation_To_File.py:56:28: unnecessary-enumerate `enumerate` index is unused, use `for x in y` instead + crazy_functions/Document_Conversation.py:289:9: return-in-generator Using `yield` and `return {value}` in a generator function can lead to confusing behavior + crazy_functions/Document_Conversation.py:337:9: return-in-generator Using `yield` and `return {value}` in a generator function can lead to confusing behavior + crazy_functions/Document_Conversation.py:438:17: return-in-generator Using `yield` and `return {value}` in a generator function can lead to confusing behavior + crazy_functions/Document_Optimize.py:112:13: return-in-generator Using `yield` and `return {value}` in a generator function can lead to confusing behavior + crazy_functions/Document_Optimize.py:359:13: return-in-generator Using `yield` and `return {value}` in a generator function can lead to confusing behavior + crazy_functions/Document_Optimize.py:448:9: return-in-generator Using `yield` and `return {value}` in a generator function can lead to confusing behavior ... 41 additional changes omitted for rule return-in-generator + crazy_functions/Image_Generate.py:183:20: if-exp-instead-of-or-operator Replace ternary `if` expression with `or` operator ... 164 additional changes omitted for project bokeh/bokeh (+4 -2 violations, +0 -0 fixes)
ruff check --no-cache --exit-zero --no-fix --output-format concise --preview --select ALL
+ src/bokeh/server/asgi.py:391:21: blocking-path-method-in-async-function Async functions should not perform blocking pathlib.Path operations - src/bokeh/server/asgi.py:391:21: blocking-path-method-in-async-function Async functions should not use pathlib.Path methods, use trio.Path or anyio.path + src/bokeh/server/views/static_handler.py:145:16: blocking-path-method-in-async-function Async functions should not perform blocking os.path operations - src/bokeh/server/views/static_handler.py:145:16: blocking-path-method-in-async-function Async functions should not use os.path methods, use trio.Path or anyio.path + tests/test_examples.py:112:34: pytest-fixture-autouse Avoid using `autouse=True` in `pytest.fixture` decorators + tests/unit/bokeh/io/test_export.py:104:33: pytest-fixture-autouse Avoid using `autouse=True` in `pytest.fixture` decorators docker/docker-py (+47 -5 violations, +0 -0 fixes)
ruff check --no-cache --exit-zero --no-fix --output-format concise --preview
+ docker/api/build.py:20:9: escape-sequence-in-docstring Use `r"""` if any backslashes in a docstring + docker/api/client.py:472:35: float-equality-comparison Unreliable floating point equality comparison `timeout == 0.0` + docker/auth.py:75:18: subclass-builtin Subclassing `dict` can be error prone, use `collections.UserDict` instead + docker/context/context.py:76:16: unnecessary-dunder-call Unnecessary dunder call to `__call__` + docker/models/containers.py:537:9: escape-sequence-in-docstring Use `r"""` if any backslashes in a docstring + docker/types/base.py:1:16: subclass-builtin Subclassing `dict` can be error prone, use `collections.UserDict` instead + docker/types/containers.py:264:18: subclass-builtin Subclassing `dict` can be error prone, use `collections.UserDict` instead + docker/types/containers.py:688:23: subclass-builtin Subclassing `dict` can be error prone, use `collections.UserDict` instead + docker/types/networks.py:54:24: subclass-builtin Subclassing `dict` can be error prone, use `collections.UserDict` instead + docker/types/networks.py:5:22: subclass-builtin Subclassing `dict` can be error prone, use `collections.UserDict` instead ... 22 additional changes omitted for rule subclass-builtin ... 42 additional changes omitted for project facebookresearch/chameleon (+5 -0 violations, +0 -0 fixes)
ruff check --no-cache --exit-zero --no-fix --output-format concise --preview
+ chameleon/inference/chameleon.py:387:26: slice-copy [*] Prefer `copy` method over slicing + chameleon/inference/stopping_criteria.py:16:28: subclass-builtin Subclassing `list` can be error prone, use `collections.UserList` instead + chameleon/inference/vqgan.py:92:32: float-equality-comparison Unreliable floating point equality comparison `temp == 1.0` + chameleon/viewer/backend/models/chameleon_distributed.py:394:17: logging-eager-conversion Unnecessary `str()` conversion when formatting with `%s` + chameleon/viewer/backend/models/chameleon_distributed.py:475:17: logging-eager-conversion Unnecessary `str()` conversion when formatting with `%s` ... Truncated remaining completed project reports due to GitHub comment length restrictions Changes by rule (56 rules affected)
Formatter (stable)✅ ecosystem check detected no format changes. Formatter (preview)✅ ecosystem check detected no format changes. |
by ecosystem round-tripbase: regressions: 1, changed: 715, improvements: 2, error changes: 2 (across 25977 files in 148 projects) ❌ regressions (built on base, now fails)dedupe —ℹ️ changed round-trip outputExpression — _by_sourcemap.py--- base/_by_sourcemap.py
+++ head/_by_sourcemap.py
@@ -78,9 +78,7 @@
... 28975 characters elided ...
"/tmp/tmpuegk30i1/Expression/out/tests/test_tagged_union.py": {"by": "sha256:adf68fcc4ac3ff05dfb3b9f856355c7bbec9f50b083417a79fe6be7f78e8bdb0", "py": "sha256:dbe410640a0b1872437c0134d78d55fd66740c68a39d0ca63df5c6f42bc757f8"},Expression — tests/test_block.py--- base/tests/test_block.py
+++ head/tests/test_block.py
@@ -323,5 +323,5 @@
mapper: Callable[[int, int], int] = lambda x, y: x + y
ys = _soundness_parametric(pipe(
- _soundness_check(block.of_seq(xs), Block),
+ _soundness_parametric(block.of_seq(xs), Block[tuple[int, int]], (0,)),
block.starmap(mapper),
), Block[int], (0,))
@@ -335,5 +335,5 @@
mapper: Callable[[int, int], int] = lambda x, y: x + y
ys = _soundness_parametric(pipe(
- _soundness_check(block.of_seq(xs), Block),
+ _soundness_parametric(block.of_seq(xs), Block[tuple[int, int]], (0,)),
block.map2(mapper),
), Block[int], (0,))
@@ -347,5 +347,5 @@
mapper: Callable[[int, int, int], int] = lambda x, y, z: x + y + z
ys = _soundness_parametric(pipe(
- _soundness_check(block.of_seq(xs), Block),
+ _soundness_parametric(block.of_seq(xs), Block[tuple[int, int, int]], (0,)),
block.map3(mapper),
), Block[int], (0,))Expression — tests/test_option_builder.py(only produced on base)Expression — tests/test_result_builder.py(only produced on base)Expression — tests/test_seq.py--- base/tests/test_seq.py
+++ head/tests/test_seq.py
@@ -510,10 +510,10 @@
nonlocal ran
ran = True
- return _soundness_parametric(seq.of_list(xs), Seq[int], (0,))
+ return _soundness_check(seq.of_list(xs), Seq)
ys = seq.delay(generator)
assert not ran
- assert list[int](ys) == xs
+ assert list(ys) == xs
assert ranPyGithub — _by_sourcemap.py--- base/_by_sourcemap.py
+++ head/_by_sourcemap.py
@@ -518,5 +518,5 @@
"/tmp/tmp3hirm2hw/PyGithub/out/openapi/conftest.py": {"by": "sha256:b7b3ce9254deaa83ee4787b0ee0511658b3a0d1aec5321906f0c6e3dc323dc38", "py": "sha256:d3a19b3f9de87d52196b54d6b4ab1467a3601a020a1e46ddbc1ce708e18dbee4"},
"/tmp/tmp3hirm2hw/PyGithub/out/scripts/fix_headers.py": {"by": "sha256:105094085c5acc16071f1de2451593a71500faa1ed75d5af681744f7732b0a38", "py": "sha256:e18e7a20a9b069e1b54d9481ccc0e6332d7418a13bc98c236dcefe35b571c178"},
- "/tmp/tmp3hirm2hw/PyGithub/out/scripts/openapi.py": {"by": "sha256:d38c9629bddaf8736664aff189f68a6721810b1f0a495d4554f1a26e85941096", "py": "sha256:2f39dacd11a5838538661d896370a5715355cdefac780cd65563973ee778ff6a"},
+ "/tmp/tmp3hirm2hw/PyGithub/out/scripts/openapi.py": {"by": "sha256:d38c9629bddaf8736664aff189f68a6721810b1f0a495d4554f1a26e85941096", "py": "sha256:54a3d0548086ba275e1366a0829130e294c9bdb69410933e13af72db52aec02b"},
"/tmp/tmp3hirm2hw/PyGithub/out/scripts/prepare-for-update-assertions.py": {"by": "sha256:dd1f8c58c01073da2d1c925f9ba265e4909ac9b3e6a2541b593af5b9cde3c906", "py": "sha256:08f68b18dd974244f15cb23c240fbb847e2bd6ada1140deb67a5c093b9fb9837"},
"/tmp/tmp3hirm2hw/PyGithub/out/scripts/sort_class.py": {"by": "sha256:fbe974b2b75d3a1d06c7b1e1ccb8708c5d288c6c73facb249bacf2bb3fc13d17", "py": "sha256:1b1c011869c7abbf49ecff378cd589f3af680e393fead308d3a3680f45ea7b85"},PyGithub — scripts/openapi.py--- base/scripts/openapi.py
+++ head/scripts/openapi.py
@@ -2052,5 +2052,5 @@
prop = self.properties.pop(0)
stmt = create_statement(prop, self_attribute)
- stmts = _soundness_check(stmts[:i], list) + [stmt] + _soundness_check(stmts[i:], list)
+ stmts = stmts[:i] + [stmt] + stmts[i:]
i = i + 1
if self.properties and self.properties[0].python_name == asserted_property:
@@ -3432,5 +3432,5 @@
return []
- for name, clazz in _soundness_check(sorted(classes.items(), key=lambda v: v[0]), list):
+ for name, clazz in _soundness_check(sorted(classes.items(), key=lambda v: _soundness_check(v[0], str)), list):
if not clazz.get("ids", []):
base_ids = get_ids(name)
@@ -4758,5 +4758,5 @@
type=HandleNewSchemas,
... 1285 characters elided ...
- choices=list(HandleNewSchemas),
+ choices=list[HandleNewSchemas](HandleNewSchemas),
)
create_method_parser.add_argument(Tanjun — _by_sourcemap.py--- base/_by_sourcemap.py
+++ head/_by_sourcemap.py
@@ -30,5 +30,5 @@
... 58995 characters elided ...
"/tmp/tmppmpt6tpp/Tanjun/out/tests/context/test_autocomplete.py": {"by": "sha256:01484543bee3deb8f43a0dc70f061f2a4352e7c8ccb0db4b1d167f1f16c276d4", "py": "sha256:bf745339b19923e500f1615b3b8e473a3032974e961a916b965bc409dbacf391"},Tanjun — tanjun/clients.py--- base/tanjun/clients.py
+++ head/tanjun/clients.py
@@ -445,5 +445,5 @@
MessageAcceptsEnum.NONE: None,
}
-assert _ACCEPTS_EVENT_TYPE_MAPPING.keys() == set(MessageAcceptsEnum)
+assert _ACCEPTS_EVENT_TYPE_MAPPING.keys() == set[MessageAcceptsEnum](MessageAcceptsEnum)Tanjun — tanjun/commands/message.py--- base/tanjun/commands/message.py
+++ head/tanjun/commands/message.py
@@ -270,5 +270,5 @@
# <<inherited docstring from tanjun.abc.MessageCommand>>.
def names(self) -> collections.Collection[str]:
- return self._names.copy()
+ return _soundness_check(self._names.copy(), list)
@property
@@ -307,5 +307,5 @@
inst = super().copy()
inst._callback = copy.copy(self._callback) # noqa: SLF001
- inst._names = self._names.copy() # noqa: SLF001
+ inst._names = _soundness_check(self._names.copy(), list) # noqa: SLF001
inst._parent = parent # noqa: SLF001
inst._parser = self._parser.copy() if self._parser else None # noqa: SLF001
@@ -451,5 +451,5 @@
def commands(self) -> collections.Collection[tanjun.MessageCommand[typing.Any]]:
# <<inherited docstring from tanjun.abc.MessageCommandGroup>>.
- return self._commands.commands.copy()
+ return _soundness_check(self._commands.commands.copy(), list)
@propertyTanjun — tanjun/commands/slash.py--- base/tanjun/commands/slash.py
+++ head/tanjun/commands/slash.py
@@ -1204,5 +1204,5 @@
def commands(self) -> collections.Collection[tanjun.BaseSlashCommand]:
# <<inherited docstring from tanjun.abc.SlashCommandGroup>>.
- return self._commands.copy().values()
+ return _soundness_check(self._commands.copy(), dict).values()
@property
@@ -1722,15 +1722,15 @@
def float_autocompletes(self) -> collections.Mapping[str, tanjun.AutocompleteSig[JustFloat]]:
# <<inherited docstring from tanjun.abc.SlashCommand>>.
- return self._float_autocompletes.copy()
+ return _soundness_check(self._float_autocompletes.copy(), dict)
@property
def int_autocompletes(self) -> collections.Mapping[str, tanjun.AutocompleteSig[int]]:
# <<inherited docstring from tanjun.abc.SlashCommand>>.
- return self._int_autocompletes.copy()
+ return _soundness_check(self._int_autocompletes.copy(), dict)
@property
def str_autocompletes(self) -> collections.Mapping[str, tanjun.AutocompleteSig[str]]:
... 1456 characters elided ...
] = {}
- for tracked_option in self._tracked_options.values():
+ for tracked_option in _soundness_iter(self._tracked_options.values(), _TrackedOption):
if not (option := ctx.options.get(tracked_option.name)):
if tracked_option.default is tanjun.NO_DEFAULT:Tanjun — tanjun/components.py--- base/tanjun/components.py
+++ head/tanjun/components.py
@@ -317,5 +317,5 @@
) -> collections.Mapping[type[hikari.Event], collections.Collection[tanjun.ListenerCallbackSig[typing.Any]]]:
# <<inherited docstring from tanjun.abc.Component>>.
- return _internal.CastedView(self._listeners, lambda x: x.copy())
+ return _internal.CastedView(self._listeners, lambda x: _soundness_check(x.copy(), list))
@property
@@ -893,5 +893,5 @@
# <<inherited docstring from tanjun.abc.Component>>.
try:
- del self._menu_commands[command.type, command.name]
+ del self._menu_commands[(command.type, command.name)]
except KeyError:
error_message = f"Command {command.name} not found"Tanjun — tanjun/context/autocomplete.py--- base/tanjun/context/autocomplete.py
+++ head/tanjun/context/autocomplete.py
@@ -206,5 +206,5 @@
def options(self) -> collections.Mapping[str, hikari.AutocompleteInteractionOption]:
# <<inherited docstring from tanjun.abc.AutocompleteContext>>.
- return self._options.copy()
+ return _soundness_check(self._options.copy(), dict)
async def fetch_channel(self) -> hikari.TextableChannel:Tanjun — tanjun/context/slash.py--- base/tanjun/context/slash.py
+++ head/tanjun/context/slash.py
@@ -1258,5 +1258,5 @@
def options(self) -> collections.Mapping[str, tanjun.SlashOption]:
# <<inherited docstring from tanjun.abc.SlashContext>>.
- return self._options.copy()
+ return _soundness_check(self._options.copy(), dict)
@propertyTanjun — tests/commands/test_slash.py--- base/tests/commands/test_slash.py
+++ head/tests/commands/test_slash.py
@@ -1630,5 +1630,5 @@
assert tracked.type is hikari.OptionType.STRING
assert tracked.default == "ayya"
- assert list(tracked.converters) == [mock_converter]
+ assert list[str](tracked.converters) == [mock_converter]
assert tracked.is_always_float is False
assert tracked.is_only_member is False
@@ -1885,5 +1885,5 @@
command.add_str_option("boom", "No u", converters=Enum)
- assert list(command._tracked_options["boom"].converters) == [Enum]
+ assert list[str](command._tracked_options["boom"].converters) == [Enum]
def test_add_int_option(self, command: tanjun.SlashCommand[typing.Any]) -> None:
@@ -1910,5 +1910,5 @@
assert tracked.type is hikari.OptionType.INTEGER
assert tracked.default == "nya"
- assert list(tracked.converters) == [mock_converter]
+ assert list[str](tracked.converters) == [mock_converter]
assert tracked.is_always_float is False
assert tracked.is_only_member is False
@@ -2106,5 +2106,5 @@
... 680 characters elided ...
command.add_float_option("sesese", "asasasa", converters=[Enum])
- assert list(command._tracked_options["sesese"].converters) == [Enum]
+ assert list[str](command._tracked_options["sesese"].converters) == [Enum]
def test_add_bool_option(self, command: tanjun.SlashCommand[typing.Any]) -> None:aiohttp — _by_sourcemap.py--- base/_by_sourcemap.py
+++ head/_by_sourcemap.py
@@ -126,5 +126,5 @@
... 63804 characters elided ...
"/tmp/tmpx7yx064n/aiohttp/out/tests/test_imports.py": {"by": "sha256:3872e2571b2a3015abc1ba81ffe1949a92788629170940480a9c1611db3f126b", "py": "sha256:bd14a250d50bccafb8c86d026c85532f545712e91a261a2a6f1a70adb814e85e"},aiohttp — aiohttp/http_parser.py--- base/aiohttp/http_parser.py
+++ head/aiohttp/http_parser.py
@@ -579,5 +579,5 @@
def get_content_length() -> int | None:
# payload length
- length_hdr = _soundness_check(msg.headers.get(CONTENT_LENGTH), (str, type(None)))
+ length_hdr = msg.headers.get(CONTENT_LENGTH)
if length_hdr is None:
return None
@@ -781,9 +781,9 @@
# as the target tokens (close, keep-alive, upgrade) are simple ASCII
# values that never contain commas.
- conn_values = _soundness_check(headers.get(hdrs.CONNECTION), (str, type(None)))
+ conn_values = headers.get(hdrs.CONNECTION)
if conn_values:
conn_tokens = {
token.lower()
- for token in _soundness_iter((part.strip(" \t") for part in _soundness_iter(conn_values.split(","), str)), str)
+ for token in (part.strip(" \t") for part in conn_values.split(","))
if token and token.isascii()
}
... 292 characters elided ...
upgrade = True
@@ -804,5 +804,5 @@
# chunking
- te = _soundness_check(headers.get(hdrs.TRANSFER_ENCODING), (str, type(None)))
+ te = headers.get(hdrs.TRANSFER_ENCODING)
if te is not None:
if self._is_chunked_te(te):aiohttp — aiohttp/multipart.py--- base/aiohttp/multipart.py
+++ head/aiohttp/multipart.py
@@ -420,5 +420,5 @@
# base64 decodes in quartets and every chunk is decoded on its own, so
# a chunk should not end mid-quartet.
- encoding = _soundness_check(self.headers.get(CONTENT_TRANSFER_ENCODING), (str, type(None)))
+ encoding = self.headers.get(CONTENT_TRANSFER_ENCODING)
if encoding and encoding.lower() == "base64":
chunk = self._align_base64_chunk(chunk, len(carry) + want)aiohttp — aiohttp/payload.py--- base/aiohttp/payload.py
+++ head/aiohttp/payload.py
@@ -662,5 +662,5 @@
self._read,
(
- min(DEFAULT_CHUNK_SIZE, remaining_content_len)
+ _soundness_check(min(DEFAULT_CHUNK_SIZE, remaining_content_len), int)
if remaining_content_len is not None
else DEFAULT_CHUNK_SIZEaiohttp — aiohttp/resolver.py--- base/aiohttp/resolver.py
+++ head/aiohttp/resolver.py
@@ -82,5 +82,5 @@
# or IPv6 is not enabled in the host
continue
- if address[3]:
+ if _soundness_check(address[3], int):
# This is essential for link-local IPv6 addresses.
# LL IPv6 is a VERY rare case. Strictly speaking, we should use
@@ -162,5 +162,5 @@
address: tuple[bytes, int] | tuple[bytes, int, int, int] = node.addr
if node.family == socket.AF_INET6:
- if len(address) > 3 and address[3]:
+ if len(address) > 3 and _soundness_check(address[3], int):
# This is essential for link-local IPv6 addresses.
# LL IPv6 is a VERY rare case. Strictly speaking, we should useaiohttp — aiohttp/test_utils.py--- base/aiohttp/test_utils.py
+++ head/aiohttp/test_utils.py
@@ -798,5 +798,5 @@
chunked = "chunked" in _soundness_check(headers.get(hdrs.TRANSFER_ENCODING, ""), str).lower()
upgrade = _soundness_check(headers.get(hdrs.CONNECTION, ""), str).lower() == "upgrade" and bool(
- _soundness_check(headers.get(hdrs.UPGRADE), (str, type(None)))
+ headers.get(hdrs.UPGRADE)
)aiohttp — tests/test_http_parser.py--- base/tests/test_http_parser.py
+++ head/tests/test_http_parser.py
@@ -1,2 +1,3 @@
+lazy from typing import Any
def _soundness_check(_v, _t):
if not isinstance(_v, _t):
@@ -21,5 +22,4 @@
lazy from collections.abc import Iterable, Iterator
lazy from contextlib import suppress
-lazy from typing import Any
lazy from unittest import mock
lazy from urllib.parse import quoteaioredis — _by_sourcemap.py--- base/_by_sourcemap.py
+++ head/_by_sourcemap.py
@@ -53,5 +53,5 @@
"/tmp/tmpuktkhdd4/aioredis/out/aioredis/client.py": {"by": "sha256:4ab41d081d399ed2f84302b5c43bbd59d6b99e56a74fa365e2facf892d820ca5", "py": "sha256:03c2bf392aec9d2aba2ee42fe90c917038467358b1b72fa5287fa9934c915e38"},
"/tmp/tmpuktkhdd4/aioredis/out/aioredis/compat.py": {"by": "sha256:ca994ab4387a0ac3beb16aa8c0b8321790f7930cdcc3b9e912394e180df8eb99", "py": "sha256:b9c2bf337c0264253577288a66b03ada923e6ce210ef6b079b445aa5213d58b9"},
- "/tmp/tmpuktkhdd4/aioredis/out/aioredis/connection.py": {"by": "sha256:ae10a0dafd9c3b88ce20c41f6968205a7a6922e0f0603a3b93a400eb96f7a574", "py": "sha256:b161f0bae30bf6e339672838e4503266e1aa333d764841a1962835badd453906"},
+ "/tmp/tmpuktkhdd4/aioredis/out/aioredis/connection.py": {"by": "sha256:ae10a0dafd9c3b88ce20c41f6968205a7a6922e0f0603a3b93a400eb96f7a574", "py": "sha256:d54c46d327a47e9bb43cdf4c9a8e4deea47faac6207a20c87dd6df95b9dc771f"},
"/tmp/tmpuktkhdd4/aioredis/out/aioredis/exceptions.py": {"by": "sha256:34839273b5deda8d51a37f7e36c7df94461526ec70c21d298e1e77556cda043e", "py": "sha256:478ed78e91d104099cf1ceedf74792496cbb8b1bc74aaf3728597ef5c0d34593"},
"/tmp/tmpuktkhdd4/aioredis/out/aioredis/lock.py": {"by": "sha256:583c756be49f801fdebc0161f30ce908dc831488d14a9afaabd3d6a402ea2e35", "py": "sha256:f651077d8d35b26269fc614ff8d40e40f79f94ee728083392c22d125a11d84ee"},aioredis — aioredis/connection.py--- base/aioredis/connection.py
+++ head/aioredis/connection.py
@@ -203,5 +203,5 @@
exception_class_or_dict = _soundness_check(self.EXCEPTION_CLASSES[error_code], (type, Mapping))
if isinstance(exception_class_or_dict, dict):
- exception_class = exception_class_or_dict.get(response, ResponseError)
+ exception_class = _soundness_check(exception_class_or_dict.get(response, ResponseError), type)
else:
exception_class = exception_class_or_dictaiortc — _by_sourcemap.py--- base/_by_sourcemap.py
+++ head/_by_sourcemap.py
@@ -113,5 +113,5 @@
"/tmp/tmpni9tmux_/aiortc/out/aiortc/rtcrtpsender.py": {"by": "sha256:526fc68e643666b7586f3ae658d35745b5c2581fca3bacf05c4130efbae701d2", "py": "sha256:5358af5b6d37759967aa0b4830d519d32e9617e6155819a202162c557947b4fe"},
"/tmp/tmpni9tmux_/aiortc/out/aiortc/rtcrtptransceiver.py": {"by": "sha256:c88f0500173d9c86074f882d6ef2bb079e92423192b3512103484880da9b9b96", "py": "sha256:31a007254199f2dbd963533ed584e59e9a90be8e287939a6b27b2a0041f58fc0"},
- "/tmp/tmpni9tmux_/aiortc/out/aiortc/rtcsctptransport.py": {"by": "sha256:06b91a0acc21b37e2580fd16a3bcf5b352fe2d04fc79b3c494e1952cfa06cd6b", "py": "sha256:065f7ab02e0eed156f851961527c2bfefb2e7b00f93548e75f02b909f5acfed0"},
+ "/tmp/tmpni9tmux_/aiortc/out/aiortc/rtcsctptransport.py": {"by": "sha256:06b91a0acc21b37e2580fd16a3bcf5b352fe2d04fc79b3c494e1952cfa06cd6b", "py": "sha256:116b6c0814a59a71c197fba7acfd94998ca8dce6f0c4fc9bfa60a2ad8d8e08ff"},
"/tmp/tmpni9tmux_/aiortc/out/aiortc/rtcsessiondescription.py": {"by": "sha256:a22257c1fbdd5a000ad964972f4346478491eb5d21b8b9119dc6322526d6d2c6", "py": "sha256:7cb1f8ba62c1307a6f405911dd301b927a8bdbc92c8b83b3650b249fcf0650df"},
"/tmp/tmpni9tmux_/aiortc/out/aiortc/rtp.py": {"by": "sha256:f562db2dbc71992bd6fafb2e5d722e13b3ac2c4320eae2a6ccc0efba3d8c6331", "py": "sha256:931573f9e6b155aa488b084c7ee0f7ec31d0a2fa69966a92749dbee0132b65e3"},aiortc — aiortc/rtcsctptransport.py--- base/aiortc/rtcsctptransport.py
+++ head/aiortc/rtcsctptransport.py
@@ -563,5 +563,5 @@
start_pos = None
while pos < len(self.reassembly):
- chunk = self.reassembly[pos]
+ chunk = _soundness_check(self.reassembly[pos], DataChunk)
if start_pos is None:
ordered = not (chunk.flags & SCTP_DATA_UNORDERED)alectryon — _by_sourcemap.py--- base/_by_sourcemap.py
+++ head/_by_sourcemap.py
@@ -62,5 +62,5 @@
"/tmp/tmpuegk30i1/alectryon/out/alectryon/json.py": {"by": "sha256:cd372b055df309193be2d6b35d0da9214d610107d53c852c30f56c0cdc70fd44", "py": "sha256:d7fb71c3e96f7ad988eb6beb467d1be8e90676aebd800dcb05456a9dd85aaddf"},
"/tmp/tmpuegk30i1/alectryon/out/alectryon/latex.py": {"by": "sha256:6cdd7734995b2eb64d93502f494cd37c8b68f6d8655902611cda6b7ef13b12c3", "py": "sha256:29eefc86acfde7b4615df9db04c88690a211dd315d7e5b73f53ec12ec39f0f97"},
- "/tmp/tmpuegk30i1/alectryon/out/alectryon/lean3.py": {"by": "sha256:aa435debc4a2e4404fc3f4a2a64bef228303b05cec5d51f397581d4c12bbd393", "py": "sha256:dc089614eb94ee3e084ba9821abff5e8900a6b730ed60a957f64bafa090b7734"},
+ "/tmp/tmpuegk30i1/alectryon/out/alectryon/lean3.py": {"by": "sha256:aa435debc4a2e4404fc3f4a2a64bef228303b05cec5d51f397581d4c12bbd393", "py": "sha256:44f138b058d566cd1976e3e1090b5c994d2232390e54c89af846d89dc9312993"},
"/tmp/tmpuegk30i1/alectryon/out/alectryon/lean4.py": {"by": "sha256:c9002b7cec9d936b92c6022df2480ba48f3f0412a6e0d318e8d3019ec4bbfb14", "py": "sha256:1920659fcdb796d3beeae63d2ad967dca78f30c00e0cb98ec9d4f40bfa8eed39"},
"/tmp/tmpuegk30i1/alectryon/out/alectryon/literate.py": {"by": "sha256:962c972177b63286cc1356954f8e1211ea29e158fab33fad1a31ecbec7c387de", "py": "sha256:40c137194977c3f4dcfc8ea87a1dd9ec39a475dec41a5aa0987f7bc0fe21b18a"},alectryon — alectryon/lean3.py--- base/alectryon/lean3.py
+++ head/alectryon/lean3.py
@@ -137,11 +137,11 @@
def _get_descendants(self, idx: int, parent: int) -> Iterable[Tuple[int, int]]:
- node: AstNode = _soundness_check(self.ast[idx], dict)
+ node: AstNode = self.ast[idx]
if node:
yield idx, parent
- if _soundness_check(node["kind"], str) in self.TACTIC_CONTAINERS:
+ if node["kind"] in self.TACTIC_CONTAINERS:
parent = idx
- if _soundness_check(node["kind"], str) not in self.DONT_RECURSE_IN:
- for cidx in _soundness_iter(node.get("children", []), int):
+ if node["kind"] not in self.DONT_RECURSE_IN:
+ for cidx in node.get("children", []):
yield from self._get_descendants(cidx, parent)
@@ -150,5 +150,5 @@
def _find_nodes_by_kind(self, *kinds):
for idx, n in enumerate(self.ast):
- if n and _soundness_check(n["kind"], str) in kinds:
+ if n and n["kind"] in kinds:
yield idx
@@ -162,10 +162,10 @@
... 1848 characters elided ...
+ commands = (self.ast[cidx] for r in _soundness_iter(roots, int) for cidx in self.ast[r].get("children", []))
+ cutoffs = [self.document.lc2offset(*c["start"]) for c in commands if "start" in c]
return self.document.split_fragments(fragments, cutoffs)antidote — _by_sourcemap.py--- base/_by_sourcemap.py
+++ head/_by_sourcemap.py
@@ -100,18 +100,18 @@
"/tmp/tmppmpt6tpp/antidote/out/antidote/core/_wiring.py": {"by": "sha256:dc0ab47eb15d6a0c11d419d8371c9dbb0d74b35131325ed9de9de694829b9c76", "py": "sha256:53d8c37d118ad02d06d24297c0847b6477901ad9dc1e4dff05dd11409420885a"},
"/tmp/tmppmpt6tpp/antidote/out/antidote/core/annotation.py": {"by": "sha256:8cbb0e7581c783ed034c05f7d685a8e33cb23bb21a6c6b1a8a1346f82f71162e", "py": "sha256:ed297f5f9917396cc6030d96e6f35e1095167a8218acab0063f55e3b8441ddaf"},
- "/tmp/tmppmpt6tpp/antidote/out/antidote/core/data.py": {"by": "sha256:99b644eba9b56d4de6f8dd3e1245f94e0c2482309e7c6c947ac22466fbd2d68d", "py": "sha256:bf4993217ae20f4e46a590fcef250a2e8450e903deb5a8615dbac9ddaa240ab3"},
+ "/tmp/tmppmpt6tpp/antidote/out/antidote/core/data.py": {"by": "sha256:d911f073a67b1412a96326fc3a8b0b0fec7ea6c40933ef02354819849411f64d", "py": "sha256:bd5dd01772a38c4a68924f20d29572c22087ea38edc22a309b9b3818930f5da2"},
... 4495 characters elided ...
"/tmp/tmppmpt6tpp/antidote/out/antidote/lib/lazy_ext/__init__.py": {"by": "sha256:71d8b14eb6dd615d43fb5393c83140e87fb2737024f379c77cec62e1eabb7f1b", "py": "sha256:2f3c2cd1a5bf6565154475b9afeeac7c6fc6758385bad20a0e6ebff8773a8791"},antidote — antidote/core/data.py--- base/antidote/core/data.py
+++ head/antidote/core/data.py
@@ -1,4 +1,4 @@
lazy from abc import abstractmethod
-lazy from typing import Callable, final
+lazy from typing import Any, Callable, final
_MISSING = object()
def _soundness_check(_v, _t):
@@ -16,5 +16,5 @@
lazy from dataclasses import dataclass
lazy from enum import Enum
-from typing import Any, cast, Optional, Sequence, TYPE_CHECKING, TypeVar
+from typing import cast, Optional, Sequence, TYPE_CHECKING, TypeVar
lazy from typing_extensions import final, get_args, get_origin, Protocol, runtime_checkableantidote — antidote/core/wiring.py--- base/antidote/core/wiring.py
+++ head/antidote/core/wiring.py
@@ -220,5 +220,5 @@
if self.ignore_type_hints:
raise ValueError("class_in_locals cannot be True if ignoring type hints!")
- type_hints_locals = dict[str, object](type_hints_locals or {})
+ type_hints_locals = dict(type_hints_locals or {})
type_hints_locals.setdefault(klass.__name__, klass)antidote — antidote/lib/interface_ext/_internal.py--- base/antidote/lib/interface_ext/_internal.py
+++ head/antidote/lib/interface_ext/_internal.py
@@ -191,5 +191,5 @@
# Extract associated predicate from the type hints
return [
- Constraint(predicate_type=_soundness_check(extract_predicate_type(constraint), type), callback=constraint)
+ Constraint(predicate_type=extract_predicate_type(constraint), callback=constraint)
for constraint in itertools.chain.from_iterable(constraints_groups.values())
]antidote — antidote/lib/interface_ext/_provider.py--- base/antidote/lib/interface_ext/_provider.py
+++ head/antidote/lib/interface_ext/_provider.py
@@ -185,5 +185,5 @@
catalog: ProviderCatalog
lock: threading.RLock
- candidates_ordered_asc: tuple[CandidateImplementation[Any]]
+ candidates_ordered_asc: tuple[CandidateImplementation[dynamic]]
default_implementation: Implementation | None
@@ -192,5 +192,5 @@
*,
catalog: ProviderCatalog,
- candidates_ordered_asc: tuple[CandidateImplementation[Any]] = _MISSING,
+ candidates_ordered_asc: tuple[CandidateImplementation[dynamic]] = _MISSING,
default_implementation: Implementation | None = None,
lock: threading.RLock | None = None,anyio — _by_sourcemap.py--- base/_by_sourcemap.py
+++ head/_by_sourcemap.py
@@ -130,5 +130,5 @@
"/tmp/tmpx7yx064n/anyio/out/tests/test_eventloop.py": {"by": "sha256:aaae8e62097ce72602c5cada0f5a8369e71ad53332d907f0f4ada68becd6badb", "py": "sha256:487101928b879defc5906d4e314aace456e9b620eb9996c0438fca030f980119"},
"/tmp/tmpx7yx064n/anyio/out/tests/test_fileio.py": {"by": "sha256:e080574af2c619cfd25b44013aaee0ddeafede748630491d819211cfc8f66c7f", "py": "sha256:65234f605e5e5d6c3cd145705c45fdd3c3d42f2014df94cad0e632e1860649bd"},
- "/tmp/tmpx7yx064n/anyio/out/tests/test_from_thread.py": {"by": "sha256:41e3ab9364383d30da945c13fc92b881630d955782ffd312f365dd4e98ea867b", "py": "sha256:3004348a6ae16811cd95de158cdb75815e1b2e66abf5ed57d09584456b33f3bd"},
+ "/tmp/tmpx7yx064n/anyio/out/tests/test_from_thread.py": {"by": "sha256:41e3ab9364383d30da945c13fc92b881630d955782ffd312f365dd4e98ea867b", "py": "sha256:724560a41b96471eed768ff17d028da74c5bcd561b52c1f5ae9a3a80d42f2c47"},
"/tmp/tmpx7yx064n/anyio/out/tests/test_functools.py": {"by": "sha256:e189f0a892ac1f2584351208c41cf7f0c1df095c5a849f4655286dd161681958", "py": "sha256:18d72005cd00e8f79e0f7cf925d02ec32ff242db1e9d03eaeeada08d68bebb39"},
"/tmp/tmpx7yx064n/anyio/out/tests/test_futures.py": {"by": "sha256:af1b33fe440c7fc9ab8735b012ebf96ad799a2587b51e9c36d5f669dd2437b32", "py": "sha256:25b8bb76c888b6ea9c5b2d292cadba68af73e2a136abfad364706ba5a0fe111d"},anyio — tests/test_from_thread.py--- base/tests/test_from_thread.py
+++ head/tests/test_from_thread.py
@@ -571,6 +571,6 @@
assert len(results) == 2
- assert isinstance(results[0], CancelledError)
- assert isinstance(results[1], CancelledError)
+ assert isinstance(_soundness_check(results[0], (BaseException, type(None))), CancelledError)
+ assert isinstance(_soundness_check(results[1], (BaseException, type(None))), CancelledError)
async def test_aexit_without_exception(self) -> None:artigraph — _by_sourcemap.py--- base/_by_sourcemap.py
+++ head/_by_sourcemap.py
@@ -75,5 +75,5 @@
"/tmp/tmpni9tmux_/artigraph/out/tests/arti/types/test_pyarrow_adapters.py": ("/tmp/tmpni9tmux_/artigraph/tests/arti/types/test_pyarrow_adapters.by", [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93]),
... 7384 characters elided ...
"/tmp/tmpni9tmux_/artigraph/out/tests/arti/versions/test_version.py": {"by": "sha256:ea498ec4c1251aa3e407fdb11fc04fd89b8def08e345bb1bb606e83332ba202d", "py": "sha256:86fa4c68434ef64e4465a21cf13e36ac099341419721396daa63ae2fd69a051c"},artigraph — arti/backends/memory.py--- base/arti/backends/memory.py
+++ head/arti/backends/memory.py
@@ -92,5 +92,5 @@
snapshot
for snapshot in _soundness_iter(partition_snapshots, StoragePartitionSnapshot)
- if _soundness_check(input_fingerprints.get(snapshot.partition_key), (Fingerprint, type(None))) == snapshot.input_fingerprint
+ if input_fingerprints.get(snapshot.partition_key) == snapshot.input_fingerprint
}
return tuple(partition_snapshots)artigraph — tests/arti/types/test_python_adapters.py--- base/tests/arti/types/test_python_adapters.py
+++ head/tests/arti/types/test_python_adapters.py
@@ -7,4 +7,8 @@
)
return _v
+
+def _soundness_iter(_it, _t):
+ for _x in _it:
+ yield _soundness_check(_x, _t)
lazy import re
@@ -46,9 +50,9 @@
def test_python_numerics() -> None:
assert isinstance(python_type_system.to_artigraph(int, hints={}), Int64)
- for int_type in (Int64, Int32, Int16, Int8):
+ for int_type in _soundness_iter((Int64, Int32, Int16, Int8), type):
assert python_type_system.to_system(int_type(), hints={}) is int
assert isinstance(python_type_system.to_artigraph(float, hints={}), Float64)
- for float_type in (Float64, Float32, Float16):
+ for float_type in _soundness_iter((Float64, Float32, Float16), type):
assert python_type_system.to_system(float_type(), hints={}) is floatasynq — _by_sourcemap.py--- base/_by_sourcemap.py
+++ head/_by_sourcemap.py
@@ -129,5 +129,5 @@
"/tmp/tmppumdngd5/asynq/out/asynq/tests/typing_example/param_spec.py": {"by": "sha256:9ef2a751beff808d416584eeefa038c4edbd08be46393e7b086bb71e9ae05248", "py": "sha256:09722a34bdb03a52e081c3ee0673d6d203169a3219213aaeb1403187e41cc6a3"},
"/tmp/tmppumdngd5/asynq/out/asynq/tests/typing_example/return_type.py": {"by": "sha256:377da89c7624effa329747864c422e36a8a7e11da28a06385ca6b9a96d13ca5c", "py": "sha256:ef40cef9a34667da72a02f77c76e2301b31422d8b6f79f336aefe04c2753bded"},
- "/tmp/tmppumdngd5/asynq/out/asynq/tools.py": {"by": "sha256:35b5e15c2ce20e7d1489384faf1f4a2c10158730ea0968da7279a722f5685862", "py": "sha256:a10d56c91ef81929e5df2a85e28d554d1cd69473675252e49412c5a08d2296d4"},
+ "/tmp/tmppumdngd5/asynq/out/asynq/tools.py": {"by": "sha256:35b5e15c2ce20e7d1489384faf1f4a2c10158730ea0968da7279a722f5685862", "py": "sha256:1544fe953d8307b38c4ed456355b203a8c733830f08406ce3fa690a995e43ed8"},
"/tmp/tmppumdngd5/asynq/out/asynq/tools.pyi": {"by": "sha256:141be2387ba7ce569098a03c5aa43ff8866b96cacbb67e67c26a0a17e43ef9a6", "py": "sha256:641a59bfecd592a373aa032376d8b775b1bd3f1deb5200a29c375d40a6af0e75"},
"/tmp/tmppumdngd5/asynq/out/asynq/utils.py": {"by": "sha256:3badf165023ebbd215d55ac7e7f1302731d61f168a52808b5533a6f29cbc14ff", "py": "sha256:603048c29abd3520e2bd155988754d22d5974fd76e59d60e28355b058571b945"},asynq — asynq/tools.py--- base/asynq/tools.py
+++ head/asynq/tools.py
@@ -132,5 +132,5 @@
keys = yield amap.asynq(key_fn, iterable)
- max_pair = _soundness_check(max(enumerate(iterable), key=lambda pair: keys[pair[0]]), tuple)
+ max_pair = _soundness_check(max(enumerate(iterable), key=lambda pair: keys[_soundness_check(pair[0], int)]), tuple)
return max_pair[1]
@@ -158,5 +158,5 @@
keys = yield amap.asynq(key_fn, iterable)
- max_pair = _soundness_check(min(enumerate(iterable), key=lambda pair: keys[pair[0]]), tuple)
+ max_pair = _soundness_check(min(enumerate(iterable), key=lambda pair: keys[_soundness_check(pair[0], int)]), tuple)
return max_pair[1]attrs — _by_sourcemap.py--- base/_by_sourcemap.py
+++ head/_by_sourcemap.py
@@ -94,5 +94,5 @@
"/tmp/tmppmpt6tpp/attrs/out/attr/setters.py": {"by": "sha256:68e7b81bd42d8a3a3d58ebb83c981e128d0555cb830ab08789c8afef0bd8b2ba", "py": "sha256:cd9e88ed1c09b516cd89d87098526fc0dded554e145d910c6bf487f0f6e14d18"},
"/tmp/tmppmpt6tpp/attrs/out/attr/setters.pyi": {"by": "sha256:248cbc3955cd19780dc44206d735891377b5063fccb2030c7f046b8d76a872ea", "py": "sha256:fe269103d826bc03cce5c2e3757bace1829b2501ca6a16122038b97947fc7a3c"},
- "/tmp/tmppmpt6tpp/attrs/out/attr/validators.py": {"by": "sha256:033814b2d808b8de44d35e812e50b9e9ccb7b3277f8dab30c365eaf04aaee089", "py": "sha256:e64e25a78c50dcae492f17f7ccf61cd244c38ab1849101cd7a78363370f1fb0e"},
+ "/tmp/tmppmpt6tpp/attrs/out/attr/validators.py": {"by": "sha256:033814b2d808b8de44d35e812e50b9e9ccb7b3277f8dab30c365eaf04aaee089", "py": "sha256:129321174767f4136d39e575b270f4acabea1c6ff8f456c6101dfbcd9b5ae2ee"},
... 1562 characters elided ...
"/tmp/tmppmpt6tpp/attrs/out/tests/test_packaging.py": {"by": "sha256:a0fc8a3929e2debbf99191434d2ae092d11fa2c2e096077d31daa26810fe2b7f", "py": "sha256:95d1d4db66e939742b5e314ac299aad4143cbfc5f8763b65c54b87fd56da569f"},attrs — attr/validators.py--- base/attr/validators.py
+++ head/attr/validators.py
@@ -185,5 +185,5 @@
msg = "'func' must be one of {}.".format(
", ".join(
- sorted((e and e.__name__) or "None" for e in set(valid_funcs))
+ _soundness_check(sorted((e and e.__name__) or "None" for e in set(valid_funcs)), list)
)
)attrs — tests/test_make.py--- base/tests/test_make.py
+++ head/tests/test_make.py
@@ -1282,10 +1282,10 @@
no = attr.field(kw_only=False)
- for cls in [OldClassNewBehavior, NewClassNewBehavior]:
+ for cls in _soundness_iter([OldClassNewBehavior, NewClassNewBehavior], type):
fs = fields_dict(cls)
assert fs["yes"].kw_only is True
assert fs["no"].kw_only is False
- for cls in [OldClassOldBehavior, NewClassOldBehavior]:
+ for cls in _soundness_iter([OldClassOldBehavior, NewClassOldBehavior], type):
fs = fields_dict(cls)bandersnatch — _by_sourcemap.py--- base/_by_sourcemap.py
+++ head/_by_sourcemap.py
@@ -56,5 +56,5 @@
"/tmp/tmpx7yx064n/bandersnatch/out/bandersnatch_storage_plugins/__init__.py": ("/tmp/tmpx7yx064n/bandersnatch/src/bandersnatch_storage_plugins/__init__.by", []),
... 12751 characters elided ...
"/tmp/tmpx7yx064n/bandersnatch/out/test_docker_runner.py": {"by": "sha256:4e7ce038a0c3862b91da38f24c0f930e0a6791b47e629d6648076fa21d746a10", "py": "sha256:d2e330ef46fd3fa965c9dc04b30ad1e3f75ba6f5880fe6edb1057ee376347485"},bandersnatch — bandersnatch_storage_plugins/s3.py--- base/bandersnatch_storage_plugins/s3.py
+++ head/bandersnatch_storage_plugins/s3.py
@@ -818,7 +818,7 @@
if not hasattr(self, "_verify_semaphore") or self._verify_semaphore is None:
- concurrency = self.configuration.getint(
+ concurrency = _soundness_check(self.configuration.getint(
"s3", "verify_concurrency", fallback=50
- )
+ ), int)
self._verify_semaphore: asyncio.Semaphore = asyncio.Semaphore(concurrency)beartype — _by_sourcemap.py--- base/_by_sourcemap.py
+++ head/_by_sourcemap.py
@@ -217,5 +217,5 @@
... 16880 characters elided ...
"/tmp/tmpn5dgw6if/beartype/out/beartype_test/a00_unit/a20_util/hint/a00_pep/__init__.py": {"by": "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "py": "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"},beartype — beartype/_decor/_nontype/decornontype.py--- base/beartype/_decor/_nontype/decornontype.py
+++ head/beartype/_decor/_nontype/decornontype.py
@@ -19,4 +19,8 @@
)
return _v
+
+def _soundness_iter(_it, _t):
+ for _x in _it:
+ yield _soundness_check(_x, _t)
@@ -193,5 +197,5 @@
# For each superclass of this object...
- for obj_base in obj_bases:
+ for obj_base in _soundness_iter(obj_bases, type):
#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
# CAUTION: Synchronize with the "PHASE 1" heuristic implemented above.beartype — beartype/_util/kind/sequence/utilseqmake.py--- base/beartype/_util/kind/sequence/utilseqmake.py
+++ head/beartype/_util/kind/sequence/utilseqmake.py
@@ -8,4 +8,12 @@
returning various kinds of sequences, both mutable and immutable).
'''
+def _soundness_check(_v, _t):
+ if not isinstance(_v, _t):
+ raise TypeError(
+ f"type soundness violation: expected {getattr(_t, '__name__', _t)}, "
+ f"got {type(_v).__name__}"
+ )
+ return _v
+
# ....................{ IMPORTS }....................
@@ -41,5 +49,5 @@
# reversing an existing list into a newly reversed list. See also:
# https://stackoverflow.com/a/3705705/2809027
- stack = sequence[::-1] # behold! the Martian smiley face emoji! ::-1
+ stack = _soundness_check(sequence[::-1], list) # behold! the Martian smiley face emoji! ::-1
# Else, this sequence is *NOT* also a list. In this case...
else:beartype — beartype_test/a00_unit/a20_util/func/test_utilfuncwrap.py--- base/beartype_test/a00_unit/a20_util/func/test_utilfuncwrap.py
+++ head/beartype_test/a00_unit/a20_util/func/test_utilfuncwrap.py
@@ -229,5 +229,5 @@
'''
- so_much_of_life_and_joy_is_lost = staticmethod(becomes_its_spoil)
+ so_much_of_life_and_joy_is_lost: staticmethod[(), str] = staticmethod(becomes_its_spoil)
# ....................{ PASS }....................
@@ -345,5 +345,5 @@
'''
- so_much_of_life_and_joy_is_lost = staticmethod(becomes_its_spoil)
+ so_much_of_life_and_joy_is_lost: staticmethod[(), str] = staticmethod(becomes_its_spoil)
# ....................{ PASS }....................black — _by_sourcemap.py--- base/_by_sourcemap.py
+++ head/_by_sourcemap.py
@@ -26,5 +26,5 @@
... 21397 characters elided ...
"/tmp/tmpni9tmux_/black/out/tests/test_ipynb.py": {"by": "sha256:12db4a150b05f7ad50c025ac3bed459eeec358d855c6cd3f9d215ed8ea48232f", "py": "sha256:a90a09f7d437bfe86ddf130dfa811eb30d2b8c88450a552bdfc1ad7b2d6f44b0"},black — black/comments.py--- base/black/comments.py
+++ head/black/comments.py
@@ -91,7 +91,7 @@
"""
total_consumed = 0
- for pc in _soundness_iter(list_comments(
+ for pc in list_comments(
leaf.prefix, is_endmarker=leaf.type == token.ENDMARKER, mode=mode
- ), ProtoComment):
+ ):
total_consumed = pc.consumed
prefix = make_simple_prefix(pc.newlines, pc.form_feed)
@@ -281,5 +281,5 @@
fmt_off_idx = None
fmt_on_idx = None
- for idx, c in enumerate[ProtoComment](all_comments):
+ for idx, c in enumerate(all_comments):
if fmt_off_idx is None and contains_fmt_directive(c.value, FMT_OFF):
fmt_off_idx = idx
@@ -296,6 +296,6 @@
return False
- comment = _soundness_check(all_comments[fmt_off_idx], ProtoComment)
- fmt_on_comment = _soundness_check(all_comments[fmt_on_idx], ProtoComment)
+ comment = all_comments[fmt_off_idx]
+ fmt_on_comment = all_comments[fmt_on_idx]
original_prefix = leaf.prefix
@@ -317,5 +317,5 @@
# Use the consumed position of the last comment before fmt:off
... 705 characters elided ...
"""
fmt_on = False
- for comment in _soundness_iter(list_comments(container.prefix, is_endmarker=False, mode=mode), ProtoComment):
+ for comment in list_comments(container.prefix, is_endmarker=False, mode=mode):
if contains_fmt_directive(comment.value, FMT_ON):
fmt_on = Trueblack — black/debug.py--- base/black/debug.py
+++ head/black/debug.py
@@ -63,6 +63,6 @@
Convenience method for debugging.
"""
- v: DebugVisitor[None] = DebugVisitor()
+ v: DebugVisitor[None] = DebugVisitor[None]()
if isinstance(code, str):
code = lib2to3_parse(code)
- list(v.visit(code))
+ list[None](v.visit(code))black — black/linegen.py--- base/black/linegen.py
+++ head/black/linegen.py
@@ -148,5 +148,5 @@
if len(self.current_line.leaves) == 1 and is_async_stmt_or_funcdef(
- self.current_line.leaves[0]
+ _soundness_check(self.current_line.leaves[0], Leaf)
):
# Special case for async def/for/with statements. `visit_async_stmt`
@@ -444,6 +444,6 @@
leaf.fmt_pass_converted_first_leaf is None
and len(self.current_line.leaves) == 1
- and self.current_line.leaves[0].type == token.LPAR
- and not self.current_line.leaves[0].value
+ and _soundness_check(self.current_line.leaves[0], Leaf).type == token.LPAR
+ and not _soundness_check(self.current_line.leaves[0], Leaf).value
)
# This is a fmt:off/on block from normalize_fmt_off - we still needblack — black/ranges.py--- base/black/ranges.py
+++ head/black/ranges.py
@@ -206,5 +206,5 @@
replacements = _NodeReplacements()
visitor = _TopLevelStatementsVisitor(lines_set, replacements)
- _ = list(visitor.visit(src_node)) # Consume all results.
+ _ = list[None](visitor.visit(src_node)) # Consume all results.
replacements.apply()
_convert_unchanged_line_by_line(src_node, lines_set)black — black/strings.py--- base/black/strings.py
+++ head/black/strings.py
@@ -388,5 +388,5 @@
body = s[first_quote_pos + len(orig_quote) : -len(orig_quote)]
if "r" in prefix.casefold():
- if _soundness_check(unescaped_new_quote.search(body), (Match, type(None))):
+ if unescaped_new_quote.search(body):
# There's at least one unescaped new_quote in this raw string
# so converting is impossible
@@ -458,5 +458,5 @@
if is_raw_fstring:
for middle in _soundness_iter(middles, Leaf):
- if _soundness_check(unescaped_new_quote.search(middle.value), (Match, type(None))):
+ if unescaped_new_quote.search(middle.value):
# There's at least one unescaped new_quote in this raw string
# so converting is impossibleblack — black/trans.py--- base/black/trans.py
+++ head/black/trans.py
@@ -1826,5 +1826,5 @@
if use_custom_breakpoints:
# Custom User Split (manual)
- csplit = custom_splits.pop(0)
+ csplit = _soundness_check(custom_splits.pop(0), CustomSplit)
break_idx = csplit.break_idx
else:black — tests/test_docs.py--- base/tests/test_docs.py
+++ head/tests/test_docs.py
@@ -77,5 +77,5 @@
preview_error = check_feature_list(
future_style,
- {feature.name for feature in set(Preview) - UNSTABLE_FEATURES},
+ {feature.name for feature in _soundness_iter(set[Preview](Preview) - UNSTABLE_FEATURES, Preview)},
"preview",
)bokeh — _by_sourcemap.py--- base/_by_sourcemap.py
+++ head/_by_sourcemap.py
@@ -461,5 +461,5 @@
"/tmp/tmpuegk30i1/bokeh/out/examples/server/app/spectrogram/audio.py": ("/tmp/tmpuegk30i1/bokeh/examples/server/app/spectrogram/audio.by", [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68]),
... 123176 characters elided ...
"/tmp/tmpuegk30i1/bokeh/out/tests/unit/bokeh/test_server.py": {"by": "sha256:03ceb5e7851b778c2e34e55c6d7b379f727a2f1fe9a803a4bcef78a9e7beb002", "py": "sha256:619b8999c9b9485a4c9b4a879aadb699729a1c104d113822027d4b3d72b20d89"},bokeh — bokeh/core/property/dataspec.py--- base/bokeh/core/property/dataspec.py
+++ head/bokeh/core/property/dataspec.py
@@ -317,5 +317,5 @@
class NullStringSpec(DataSpec):
def __init__(self, default: Any = None, *, help: str | None = None) -> None:
- super().__init__(Nullable(String), default=default, help=help)
+ super().__init__(Nullable[str](String), default=default, help=help)
class StringSpec(DataSpec):
@@ -413,5 +413,5 @@
def __init__(self, default: Any, *, help: str | None = None) -> None:
- super().__init__(Nullable(HatchPatternType), default=default, help=help)
+ super().__init__(Nullable[str](HatchPatternType), default=default, help=help)
class MarkerSpec(DataSpec):
@@ -541,5 +541,5 @@
def __init__(self, default: Any = None, units_default: Any = "data", *, help: str | None = None) -> None:
super().__init__(default=default, units_default=units_default, help=help)
- self.value_type = Nullable(Float)
+ self.value_type = Nullable[int | float](Float)
self._type_params = [Null(), *self._type_params]bokeh — bokeh/core/property/visual.py--- base/bokeh/core/property/visual.py
+++ head/bokeh/core/property/visual.py
@@ -242,6 +242,6 @@
Tuple(Float, Float),
- Tuple(Nullable(Float), Float),
- Tuple(Float, Nullable(Float)),
+ Tuple(Nullable[int | float](Float), Float),
+ Tuple(Float, Nullable[int | float](Float)),
Tuple(TimeDelta, TimeDelta),bokeh — bokeh/core/property_aliases.py--- base/bokeh/core/property_aliases.py
+++ head/bokeh/core/property_aliases.py
@@ -71,5 +71,5 @@
type PixelsType = int
-Pixels = NonNegative(Int)
+Pixels = NonNegative[int](Int)
type HAnchorType = enums.AlignType | enums.HAlignType | PercentType
@@ -121,8 +121,8 @@
Tuple(Pixels, Pixels, Pixels, Pixels),
Struct(
- top_left=Optional(Pixels),
- top_right=Optional(Pixels),
- bottom_right=Optional(Pixels),
- bottom_left=Optional(Pixels),
+ top_left=Optional[int](Pixels),
+ top_right=Optional[int](Pixels),
+ bottom_right=Optional[int](Pixels),
+ bottom_left=Optional[int](Pixels),
),
)
@@ -137,13 +137,13 @@
Tuple(Pixels, Pixels),
Struct(
- x=Optional(Pixels),
- y=Optional(Pixels),
+ x=Optional[int](Pixels),
+ y=Optional[int](Pixels),
),
Tuple(Pixels, Pixels, Pixels, Pixels),
Struct(
- left=Optional(Pixels),
- right=Optional(Pixels),
- top=Optional(Pixels),
- bottom=Optional(Pixels),
+ left=Optional[int](Pixels),
+ right=Optional[int](Pixels),
+ top=Optional[int](Pixels),
+ bottom=Optional[int](Pixels),
),
)bokeh — bokeh/core/property_mixins.py--- base/bokeh/core/property_mixins.py
+++ head/bokeh/core/property_mixins.py
@@ -289,5 +289,5 @@
hatch_alpha: Alpha = Alpha(help=_alpha_help % "hatching")
hatch_scale: Size = Size(default=12.0, help=_hatch_scale_help)
- hatch_pattern = Nullable(String, help=_hatch_pattern_help) # String to accommodate user custom values
+ hatch_pattern: Nullable[str] = Nullable[str](String, help=_hatch_pattern_help) # String to accommodate user custom values
hatch_weight: Size = Size(default=1.0, help=_hatch_weight_help)
hatch_extra = Dict(String, Instance("bokeh.models.textures.Texture"))bokeh — bokeh/model/model.py--- base/bokeh/model/model.py
+++ head/bokeh/model/model.py
@@ -161,5 +161,5 @@
return self._id
- name = Nullable(String, help="""\
+ name: Nullable[str] = Nullable[str](String, help="""\
An arbitrary, user-supplied name for this model.
@@ -230,5 +230,5 @@
""")
- subscribed_events = Set(String, help="""\
+ subscribed_events: Set[str] = Set[str](String, help="""\
Collection of events that are subscribed to by Python callbacks. This is
the set of events that will be communicated from BokehJS back to Pythonbokeh — bokeh/models/annotations/dimensional.py--- base/bokeh/models/annotations/dimensional.py
+++ head/bokeh/models/annotations/dimensional.py
@@ -74,13 +74,13 @@
super().__init__(**kwargs)
- ticks = Required(List(Float), help="""\
+ ticks: Required[list[int | float]] = Required[list[int | float]](List[int | float](Float), help="""\
Preferred values to choose from in non-exact mode.\
""")
- include = Nullable(List(String), default=None, help="""\
+ include: Nullable[list[str]] = Nullable[list[str]](List[str](String), default=None, help="""\
An optional subset of preferred units from the basis.\
""")
- exclude = List(String, default=[], help="""\
+ exclude: List[str] = List[str](String, default=[], help="""\
A subset of units from the basis to avoid.\
""")
@@ -125,9 +125,9 @@
super().__init__(**kwargs)
- base_unit = Required(String, help="""\
+ base_unit: Required[str] = Required[str](String, help="""\
The short name of the base unit, e.g. ``"m"`` for meters or ``"eV"`` for electron volts.\
""")
- full_unit = Nullable(String, default=None, help="""\
+ full_unit: Nullable[str] = Nullable[str](String, default=None, help="""\
The full name of the base unit, e.g. ``"meter"`` or ``"electronvolt"``.\
""")bokeh — bokeh/models/annotations/geometry.py--- base/bokeh/models/annotations/geometry.py
+++ head/bokeh/models/annotations/geometry.py
@@ -223,5 +223,5 @@
""")
- min_width: NonNegative[int] = NonNegative[int](Float, default=0, help="""\
+ min_width: NonNegative[int | float] = NonNegative[int | float](Float, default=0, help="""\
Allows to set the minimum width of the box.
@@ -230,5 +230,5 @@
""")
- min_height: NonNegative[int] = NonNegative[int](Float, default=0, help="""\
+ min_height: NonNegative[int | float] = NonNegative[int | float](Float, default=0, help="""\
Allows to set the maximum width of the box.
@@ -469,9 +469,9 @@
super().__init__(*args, **kwargs)
- gradient = Nullable(Float, help="""\
+ gradient: Nullable[int | float] = Nullable[int | float](Float, help="""\
The gradient of the line, in |data units|\
""")
- y_intercept = Nullable(Float, help="""\
+ y_intercept: Nullable[int | float] = Nullable[int | float](Float, help="""\
The y intercept of the line, in |data units|\
""")bokeh — bokeh/models/annotations/legends.py--- base/bokeh/models/annotations/legends.py
+++ head/bokeh/models/annotations/legends.py
@@ -10,4 +10,5 @@
from typing import Any, TYPE_CHECKING
if TYPE_CHECKING:
+ from typing import Never
import types
@@ -292,10 +293,10 @@
""")
- display_low = Nullable(Float, help="""\
+ display_low: Nullable[int | float] = Nullable[int | float](Float, help="""\
The lowest value to display in the color bar. The whole of the color entry
containing this value is shown.\
""")
- display_high = Nullable(Float, help="""\
+ display_high: Nullable[int | float] = Nullable[int | float](Float, help="""\
The highest value to display in the color bar. The whole of the color entry
containing this value is shown.\
@@ -328,5 +329,5 @@
""")
- levels = Seq(Float, default=[], help="""\
+ levels: Seq[int | float, list[Never]] = Seq(Float, default=[], help="""\
Levels at which the contours are calculated.\
""")
@@ -354,5 +355,5 @@
""")
- index = Nullable(Int, help="""\
+ index: Nullable[int] = Nullable[int](Int, help="""\
The column data index to use for drawing the representative items.
@@ -423,5 +424,5 @@
""")
- title = Nullable(String, help="""\
+ title: Nullable[str] = Nullable[str](String, help="""\
The title text to render.\
""")bokeh — bokeh/models/callbacks.py--- base/bokeh/models/callbacks.py
+++ head/bokeh/models/callbacks.py
@@ -131,5 +131,5 @@
""")
- code = Required(String)(help="""\
+ code = Required[str](String)(help="""\
A snippet of JavaScript code to execute in the browser.
@@ -269,5 +269,5 @@
""")
- attr: str = Required(String, help="""\
+ attr: str = Required[str](String, help="""\
The property to modify.\
""")bokeh — bokeh/models/css.py--- base/bokeh/models/css.py
+++ head/bokeh/models/css.py
@@ -68,5 +68,5 @@
super().__init__(*args, **kwargs)
- css = Required(String, help="""\
+ css: Required[str] = Required[str](String, help="""\
The contents of this stylesheet.\
""")
@@ -86,5 +86,5 @@
super().__init__(*args, **kwargs)
- url = Required(String, help="""\
+ url: Required[str] = Required[str](String, help="""\
The location of an external stylesheet.\
""")
@@ -121,209 +121,209 @@
super().__init__(*args, **kwargs)
- align_content = Nullable(String)
- align_items = Nullable(String)
- align_self = Nullable(String)
- alignment_baseline = Nullable(String)
- all = Nullable(String)
- animation = Nullable(String)
- animation_delay = Nullable(String)
- animation_direction = Nullable(String)
- animation_duration = Nullable(String)
- animation_fill_mode = Nullable(String)
- animation_iteration_count = Nullable(String)
- animation_name = Nullable(String)
- animation_play_state = Nullable(String)
- animation_timing_function = Nullable(String)
... 29921 characters elided ...
+ word_spacing: Nullable[str] = Nullable[str](String)
+ word_wrap: Nullable[str] = Nullable[str](String)
+ writing_mode: Nullable[str] = Nullable[str](String)
+ z_index: Nullable[str] = Nullable[str](String)
#-----------------------------------------------------------------------------bokeh — bokeh/models/dom.py--- base/bokeh/models/dom.py
+++ head/bokeh/models/dom.py
@@ -87,5 +87,5 @@
super().__init__(*args, **kwargs)
- style: Either = Either(Instance(Styles), Dict(String, String), default={})
+ style: Either = Either(Instance(Styles), Dict[str, str](String, String), default={})
children = List(Either(String, Instance(DOMNode), Instance(UIElement)), default=[])
@@ -159,9 +159,9 @@
""")
- attr = Required(String, help="""\
+ attr: Required[str] = Required[str](String, help="""\
The name of the property whose value will be observed.\
""")
- format = Nullable(String, default=None, help="""\
+ format: Nullable[str] = Nullable[str](String, default=None, help="""\
Optional format string, which is equivalent to using ``"@{field}{format}"``.\
""")
@@ -205,9 +205,9 @@
super().__init__(*args, **kwargs)
- field = Required(String, help="""\
+ field: Required[str] = Required[str](String, help="""\
The name of the field to reference, which is equivalent to using ``"@{field}``.\
""")
- format = Nullable(String, default=None, help="""\
+ format: Nullable[str] = Nullable[str](String, default=None, help="""\
Optional format string, which is equivalent to using ``"@{field}{format}"``.\
""")bokeh — bokeh/models/filters.py--- base/bokeh/models/filters.py
+++ head/bokeh/models/filters.py
@@ -169,5 +169,5 @@
'''
- column_name = Required(String, help="""\
+ column_name: Required[str] = Required[str](String, help="""\
The name of the column to perform the group filtering operation on.\
""")💥 fails to round-trip (unchanged from base)
669 finding(s) omitted to fit GitHub's 65536-character comment limit. Every finding, with nothing elided, is in the |
86507e1 to
e8f1a60
Compare
e8f1a60 to
3cb38f0
Compare
No description provided.